Skills Plugins MCP Prompt Model 博客 我的中心

lex-data

Represent, parse, serialize, hash, or convert AT Protocol data values with `@atproto/lex`. Use whenever code touches CIDs, raw bytes, `$link` / `$bytes` JSON, CBOR / DRISL encoding, blob references, or AT Protocol identifier and datetime strings — DIDs, handles, AT URIs, NSIDs, TIDs, record keys, `createdAt` / `indexedAt`. Applies when the ask sounds like "serialize this record", "hash these bytes", "why is this datetime rejected", "count the characters in this field", or when replacing `multiformats` CIDs, `new Date().toISOString()`, or hand-rolled base64. Read it before typing a DID, AT URI, or datetime as a bare `string`.

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=bluesky-social-atproto-agents-skills-lex-data-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name lex-data description Represent, parse, serialize, hash, or convert AT Protocol data values with `@atproto/lex`. Use whenever code touches CIDs, raw bytes, `$link` / `$bytes` JSON, CBOR / DRISL encoding, blob references, or AT Protocol identifier and datetime strings — DIDs, handles, AT URIs, NSIDs, TIDs, record keys, `createdAt` / `indexedAt`. Applies when the ask sounds like "serialize this record", "hash these bytes", "why is this datetime rejected", "count the characters in this field", or when replacing `multiformats` CIDs, `new Date().toISOString()`, or hand-rolled base64. Read it before typing a DID, AT URI, or datetime as a bare `string`. disable-model-invocation false Data model: types, CIDs, JSON, CBOR, identifier strings, blobs The AT Protocol data model is JSON plus two primitives — CIDs (content-addressed links) and bytes (raw binary) — encodable as JSON or as CBOR. Which package exports what @atproto/lex re-exports lex-data , lex-json , lex-schema and lex-client , so a package that already depends on it needs no extra import path. @atproto/lex-cbor is not re-exported — depend on it explicitly. Symbols Defined in Reachable via @atproto/lex LexValue , Cid , blob refs, base64/utf8 helpers, LexError @atproto/lex-data yes lexParse , lexStringify , jsonToLex , lexToJson @atproto/lex-json yes Identifier & datetime string types + guards @atproto/syntax , re-exported by @atproto/lex-schema yes encode , decode , decodeAll , cidForLex @atproto/lex-cbor no Low-level packages ( repo , common , xrpc-server ) import @atproto/lex-data directly to avoid pulling in the client and schema layers. [!NOTE] This repo sets verbatimModuleSyntax: true , so type-only names need the type modifier — import { type DidString, isDidString } from '@atproto/lex' . All examples below follow that form. Lex value types import { type LexValue , type TypedLexMap , isLexValue, isTypedLexMap, } from '@atproto/lex' // LexScalar: number (integers only) | string | boolean | null | Cid | Uint8Array // LexValue: LexScalar | LexValue[] | { [key: string]?: LexValue } // LexMap: { [key: string]?: LexValue } // TypedLexMap: LexMap & { $type: string } isLexValue , isLexMap , isLexArray and isLexScalar take unknown ; isTypedLexMap takes a LexValue , so narrow with isLexValue first when the input is untyped. isLexValue walks the whole structure and rejects cycles, non-integer numbers, and non-plain objects ( Date , class instances, functions) — it is not a cheap check, so avoid it on hot paths where a schema already validates the value. CIDs Cid is an interface, not a class. @atproto/lex-data defines it rather than re-exporting multiformats ' CID , because that class breaks under node16 / bundler module resolution. Treat CID and asMultiformatsCID as deprecated escape hatches. import { type Cid , asCid, decodeCid, ifCid, isCid, parseCid, parseCidSafe, } from '@atproto/lex' parseCid (str) // Cid — throws on invalid parseCidSafe (str) // Cid | null decodeCid (bytes) // Cid from binary form — throws on invalid isCid (value) // type guard ifCid (value) // Cid | null asCid (value) // Cid — throws on invalid Each accepts a { flavor } option that additionally constrains the CID, which is how you enforce that a blob CID really is a blob CID rather than trusting the caller: 'raw' — v1 + raw multicodec (blob content) 'cbor' — v1 + dag-cbor + sha256 (records, MST nodes) 'dasl' — either codec, v1 + sha256 For strings you already hold, validateCidString(str, options) returns a boolean and also checks the string is the canonical encoding; ensureValidCidString throws instead. Creating CIDs — hashing is async because it goes through WebCrypto: import { cidForCbor, cidForRawBytes, cidForRawHash, isCidForBytes, } from '@atproto/lex' import { cidForLex } from '@atproto/lex-cbor' await cidForLex (record) // CBOR-encode then hash — the usual entry point await cidForCbor (cborBytes) // hash bytes that are already CBOR await cidForRawBytes (blobBytes) // raw CID for blob content cidForRawHash (sha256Digest) // sync, when you already streamed the hash await isCidForBytes (cid, bytes) // verify a CID matches its content In Lex JSON, CIDs are encoded as { "$link": "bafyrei..." } . Bytes Binary data is Uint8Array ; JSON-encoded as { "$bytes": "base64..." } . @atproto/lex-data ships the byte utilities so packages don't add their own base64 dependency: toBase64 / fromBase64 (both take an optional 'base64' | 'base64url' alphabet), utf8ToBase64 / utf8FromBase64 , utf8FromBytes , ui8Concat , ui8Equals , asUint8Array , ifUint8Array . JSON ↔ Lex Function Direction Input Output lexParse JSON string → Lex string LexValue (with Cid , Uint8Array ) lexStringify Lex → JSON string LexValue string jsonToLex parsed JSON → Lex plain JS object LexValue lexToJson Lex → plain JS LexValue plain JS object lexParse<T>() takes a type parameter, so no as cast is needed: import { lexParse, lexStringify } from '@atproto/lex' const sub = lexParse<app. bsky . notification . defs . SubjectActivitySubscription >(json) const out = lexStringify ({ ref : someCid, data : someBytes }) lexParse and jsonToLex accept { strict } , defaulting to false : malformed $link / $bytes objects and non-integer numbers pass through unchanged rather than throwing. Pass { strict: true } when the input is untrusted and a silently-wrong value would be worse than an exception. lexParseJsonBytes(bytes, options) is the same parse starting from UTF-8 bytes. Field-level encode/decode is rarely needed, but note the return contract — these signal failure by returning undefined , they do not throw: import { encodeLexBytes, encodeLexLink, parseLexBytes, parseLexLink, } from '@atproto/lex' parseLexLink ({ $link : 'bafy...' }) // Cid | undefined parseLexBytes ({ $bytes : 'SGVsbG8=' }) // Uint8Array | undefined encodeLexLink (someCid) // { $link: '...' } encodeLexBytes ( new Uint8Array ([ 1 , 2 , 3 ])) // { $bytes: '...' } CBOR (DRISL) Use CBOR for repo storage, signed records, CAR files, and event frames — anywhere DRISL deterministic encoding is required. Add @atproto/lex-cbor as a dependency; it is not reachable through @atproto/lex . import { type LexValue } from '@atproto/lex' import { cidForLex, decode, decodeAll, encode } from '@atproto/lex-cbor' const bytes : Uint8Array = encode (someLexValue) const value = decode<{ foo : LexValue }>(bytes) // Concatenated values (CAR blocks, subscription frames) for ( const frame of decodeAll (buffer)) { /* … */ } encode throws on anything the AT data model forbids: non-string map keys, undefined , and non-integer numbers. That strictness is the point — it is what makes the resulting CID stable. Datetime strings DatetimeString is the branded type for AT Protocol datetimes. Date.prototype.toISOString() is not guaranteed to conform (years outside 0–9999 serialize with a ±YYYYYY prefix), so route Date → string through the helpers rather than calling toISOString() directly: import { type DatetimeString , asDatetimeString, currentDatetimeString, ifDatetimeString, isDatetimeString, toDatetimeString, } from '@atproto/lex' currentDatetimeString () // now toDatetimeString (date) // throws InvalidDatetimeError on an out-of-range date asDatetimeString (str) // validates + brands a string, throws on invalid isDatetimeString (value) // type guard ifDatetimeString (value) // DatetimeString | undefined isDatetimeStringLenient accepts ISO-ish strings that the spec rejects (e.g. missing a timezone) — use it when reading legacy records, not when writing. For repairing bad historical createdAt values, normalizeDatetime / normalizeDatetimeAlways live in @atproto/syntax only; they are not re-exported from @atproto/lex . Use DatetimeString on record and DB row types so a raw string can't drift in: import type { DatetimeString , DidString } from '@atproto/lex' interface Row { did : DidString indexedAt : DatetimeString } Identifier strings Nominal string types keep unvalidated string s from being passed where a validated identifier is expected. Type Format Guard DidString did:method:specific-id isDidString HandleString DNS-style handle isHandleString AtIdentifierString DID or handle isAtIdentifierString AtUriString at://… isAtUriString UriString any scheme:… URI isUriString NsidString app.bsky.feed.post isNsidString TidString timestamp identifier isTidString RecordKeyString rkey (TID or literal) isRecordKeyString CidString CID in string form isCidString LanguageString BCP-47 tag ( en , pt-BR ) isLanguageString DatetimeString AT Proto datetime isDatetimeString Only AtUriString , AtIdentifierString and DatetimeString also ship as… / assert… / if… variants. For the rest, the generic format helpers cover the same ground: import { asStringFormat, ifStringFormat, isStringFormat } from '@atproto/lex' isStringFormat (value, 'did' ) // narrows to DidString asStringFormat (value, 'nsid' ) // throws TypeError on invalid ifStringFormat (value, 'handle' ) // HandleString | undefined isAtUriString , isLanguageString and isStringFormat accept { strict: false } for a lenient pass that tolerates non-conforming real-world data. [!NOTE] These types are defined in @atproto/syntax and re-exported through @atproto/lex . Import from @atproto/lex where the package already depends on it — that keeps identifier types and generated schemas coming from one place and avoids adding a @atproto/syntax dependency. Boundaries Protobuf messages, data-plane responses and Kysely rows all arrive as bare string . Brand them once at the boundary so downstream code is typed, instead of asserting at each use: dids : dids as DidString [], post : { uri : item. uri as AtUriString , cid : item. cid || undefined }, An as cast is appropriate where the value provably came from a validated source (your own DB, a schema-validated response). Where it did not — env vars, CLI args, user input — run the guard: assert(isDidString(serverDid)) . Blob references Two shapes coexist on the network: type TypedBlobRef = { $type : 'blob' ; ref : Cid ; mimeType : string ; size : number } type LegacyBlobRef = { cid : string ; mimeType : string } // no $type, no size type BlobRef = TypedBlobRef | LegacyBlobRef New uploads are always TypedBlobRef — the PDS uploadBlob endpoint returns one. Reading code has to tolerate both, which is what the format-agnostic accessors are for: import { type BlobRef , enumBlobRefs, getBlobCid, getBlobCidString, getBlobMime, getBlobSize, isLegacyBlobRef, isTypedBlobRef, } from '@atproto/lex' getBlobCid (blob) // Cid — parses the string for legacy refs, so it can throw getBlobCidString (blob) // string — skips the parse, prefer it when you only need the string getBlobMime (blob) // string getBlobSize (blob) // number | undefined — legacy refs carry no size // Deep-walk a record for its blobs (what the PDS does on record write/import) for ( const ref of enumBlobRefs (record, { allowLegacy : true , strict : false })) { /* … */ } enumBlobRefs skips legacy refs unless allowLegacy: true . BlobRef is an interface, so instanceof does not apply — use isBlobRef / isTypedBlobRef / isLegacyBlobRef . What strict means for blobs The word means different things at two layers, and conflating them causes confusing validation failures: On the guards ( isBlobRef , isTypedBlobRef , isLegacyBlobRef ,
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。