@metalabel/dfos-protocol 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,258 @@
1
+ import {
2
+ base64urlDecode,
3
+ base64urlEncode,
4
+ createJwt,
5
+ isValidEd25519Signature,
6
+ verifyJwt
7
+ } from "./chunk-ZXXP5W5N.js";
8
+
9
+ // src/credentials/schemas.ts
10
+ import { z } from "zod";
11
+ var MAX_DID = 256;
12
+ var MAX_AUD = 512;
13
+ var MAX_CONTENT_ID = 256;
14
+ var VC_TYPE_CONTENT_WRITE = "DFOSContentWrite";
15
+ var VC_TYPE_CONTENT_READ = "DFOSContentRead";
16
+ var DFOSCredentialType = z.enum([VC_TYPE_CONTENT_WRITE, VC_TYPE_CONTENT_READ]);
17
+ var AuthTokenClaims = z.strictObject({
18
+ /** Issuer — the DID proving identity */
19
+ iss: z.string().max(MAX_DID),
20
+ /** Subject — same as iss for auth tokens */
21
+ sub: z.string().max(MAX_DID),
22
+ /** Audience — target relay hostname (prevents cross-relay replay) */
23
+ aud: z.string().max(MAX_AUD),
24
+ /** Expiration — unix seconds, short-lived (minutes) */
25
+ exp: z.number().int().positive(),
26
+ /** Issued at — unix seconds */
27
+ iat: z.number().int().positive()
28
+ });
29
+ var ContentWriteSubject = z.strictObject({
30
+ /** Optional content chain narrowing — if absent, grants broad write access */
31
+ contentId: z.string().max(MAX_CONTENT_ID).optional()
32
+ });
33
+ var ContentReadSubject = z.strictObject({
34
+ /** Optional content chain narrowing — if absent, grants broad read access */
35
+ contentId: z.string().max(MAX_CONTENT_ID).optional()
36
+ });
37
+ var VCClaim = z.strictObject({
38
+ "@context": z.tuple([z.literal("https://www.w3.org/ns/credentials/v2")]),
39
+ type: z.tuple([z.literal("VerifiableCredential"), DFOSCredentialType]).transform((t) => t),
40
+ credentialSubject: z.union([ContentWriteSubject, ContentReadSubject])
41
+ });
42
+ var CredentialClaims = z.strictObject({
43
+ /** Issuer — the DID granting the credential */
44
+ iss: z.string().max(MAX_DID),
45
+ /** Subject — the DID receiving the credential */
46
+ sub: z.string().max(MAX_DID),
47
+ /** Expiration — unix seconds */
48
+ exp: z.number().int().positive(),
49
+ /** Issued at — unix seconds */
50
+ iat: z.number().int().positive(),
51
+ /** Verifiable credential claim */
52
+ vc: VCClaim
53
+ });
54
+
55
+ // src/credentials/auth-token.ts
56
+ var createAuthToken = async (options) => {
57
+ if (!options.kid.includes("#")) {
58
+ throw new Error("kid must be a DID URL (did:dfos:xxx#key_yyy)");
59
+ }
60
+ const kidDid = options.kid.substring(0, options.kid.indexOf("#"));
61
+ if (kidDid !== options.iss) {
62
+ throw new Error("kid DID does not match iss");
63
+ }
64
+ const now = options.iat ?? Math.floor(Date.now() / 1e3);
65
+ const header = { alg: "EdDSA", typ: "JWT", kid: options.kid };
66
+ const payload = {
67
+ iss: options.iss,
68
+ sub: options.iss,
69
+ aud: options.aud,
70
+ exp: options.exp,
71
+ iat: now
72
+ };
73
+ return createJwt({ header, payload, sign: options.sign });
74
+ };
75
+ var verifyAuthToken = (options) => {
76
+ const { header, payload } = verifyJwt({
77
+ token: options.token,
78
+ publicKey: options.publicKey,
79
+ audience: options.audience,
80
+ ...options.currentTime !== void 0 ? { currentTime: options.currentTime } : {}
81
+ });
82
+ const result = AuthTokenClaims.safeParse(payload);
83
+ if (!result.success) {
84
+ const messages = result.error.issues.map((e) => e.message).join(", ");
85
+ throw new AuthTokenVerificationError(`invalid auth token claims: ${messages}`);
86
+ }
87
+ const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
88
+ if (result.data.iat > currentTime) {
89
+ throw new AuthTokenVerificationError("auth token not yet valid (iat is in the future)");
90
+ }
91
+ const kid = header.kid;
92
+ if (!kid || !kid.includes("#")) {
93
+ throw new AuthTokenVerificationError("auth token kid must be a DID URL");
94
+ }
95
+ const kidDid = kid.substring(0, kid.indexOf("#"));
96
+ if (kidDid !== result.data.iss) {
97
+ throw new AuthTokenVerificationError("auth token kid DID does not match iss");
98
+ }
99
+ return {
100
+ iss: result.data.iss,
101
+ aud: result.data.aud,
102
+ exp: result.data.exp,
103
+ kid
104
+ };
105
+ };
106
+ var AuthTokenVerificationError = class extends Error {
107
+ constructor(message) {
108
+ super(message);
109
+ this.name = "AuthTokenVerificationError";
110
+ }
111
+ };
112
+
113
+ // src/credentials/credential.ts
114
+ var createCredential = async (options) => {
115
+ if (!options.kid.includes("#")) {
116
+ throw new Error("kid must be a DID URL (did:dfos:xxx#key_yyy)");
117
+ }
118
+ const kidDid = options.kid.substring(0, options.kid.indexOf("#"));
119
+ if (kidDid !== options.iss) {
120
+ throw new Error("kid DID does not match iss");
121
+ }
122
+ const now = options.iat ?? Math.floor(Date.now() / 1e3);
123
+ const header = { alg: "EdDSA", typ: "vc+jwt", kid: options.kid };
124
+ const credentialSubject = {};
125
+ if (options.contentId) {
126
+ credentialSubject.contentId = options.contentId;
127
+ }
128
+ const payload = {
129
+ iss: options.iss,
130
+ sub: options.sub,
131
+ exp: options.exp,
132
+ iat: now,
133
+ vc: {
134
+ "@context": ["https://www.w3.org/ns/credentials/v2"],
135
+ type: ["VerifiableCredential", options.type],
136
+ credentialSubject
137
+ }
138
+ };
139
+ const headerB64 = base64urlEncode(JSON.stringify(header));
140
+ const payloadB64 = base64urlEncode(JSON.stringify(payload));
141
+ const signingInput = `${headerB64}.${payloadB64}`;
142
+ const signingInputBytes = new TextEncoder().encode(signingInput);
143
+ const signatureBytes = await options.sign(signingInputBytes);
144
+ const signatureB64 = base64urlEncode(signatureBytes);
145
+ return `${signingInput}.${signatureB64}`;
146
+ };
147
+ var verifyCredential = (options) => {
148
+ const parts = options.token.split(".");
149
+ if (parts.length !== 3) {
150
+ throw new CredentialVerificationError("invalid token format");
151
+ }
152
+ const [headerB64, payloadB64, signatureB64] = parts;
153
+ let header;
154
+ let payload;
155
+ try {
156
+ header = JSON.parse(new TextDecoder().decode(base64urlDecode(headerB64)));
157
+ payload = JSON.parse(new TextDecoder().decode(base64urlDecode(payloadB64)));
158
+ } catch {
159
+ throw new CredentialVerificationError("failed to decode token");
160
+ }
161
+ if (header.alg !== "EdDSA") {
162
+ throw new CredentialVerificationError(`unsupported algorithm: ${header.alg}`);
163
+ }
164
+ if (header.typ !== "vc+jwt") {
165
+ throw new CredentialVerificationError(`invalid typ: ${header.typ}`);
166
+ }
167
+ const signingInput = `${headerB64}.${payloadB64}`;
168
+ const signingInputBytes = new TextEncoder().encode(signingInput);
169
+ let signatureBytes;
170
+ try {
171
+ signatureBytes = base64urlDecode(signatureB64);
172
+ } catch {
173
+ throw new CredentialVerificationError("failed to decode signature");
174
+ }
175
+ const isValid = isValidEd25519Signature(signingInputBytes, signatureBytes, options.publicKey);
176
+ if (!isValid) {
177
+ throw new CredentialVerificationError("invalid signature");
178
+ }
179
+ const result = CredentialClaims.safeParse(payload);
180
+ if (!result.success) {
181
+ const messages = result.error.issues.map((e) => e.message).join(", ");
182
+ throw new CredentialVerificationError(`invalid credential claims: ${messages}`);
183
+ }
184
+ const claims = result.data;
185
+ const kid = header.kid;
186
+ if (!kid || !kid.includes("#")) {
187
+ throw new CredentialVerificationError("credential kid must be a DID URL");
188
+ }
189
+ const kidDid = kid.substring(0, kid.indexOf("#"));
190
+ if (kidDid !== claims.iss) {
191
+ throw new CredentialVerificationError("credential kid DID does not match iss");
192
+ }
193
+ const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
194
+ if (claims.iat > currentTime) {
195
+ throw new CredentialVerificationError("credential not yet valid (iat is in the future)");
196
+ }
197
+ if (claims.exp <= currentTime) {
198
+ throw new CredentialVerificationError("credential expired");
199
+ }
200
+ if (options.subject !== void 0 && claims.sub !== options.subject) {
201
+ throw new CredentialVerificationError(
202
+ `subject mismatch: expected ${options.subject}, got ${claims.sub}`
203
+ );
204
+ }
205
+ const vcType = claims.vc.type[1];
206
+ if (options.expectedType !== void 0 && vcType !== options.expectedType) {
207
+ throw new CredentialVerificationError(
208
+ `type mismatch: expected ${options.expectedType}, got ${vcType}`
209
+ );
210
+ }
211
+ const contentId = claims.vc.credentialSubject.contentId;
212
+ return {
213
+ iss: claims.iss,
214
+ sub: claims.sub,
215
+ exp: claims.exp,
216
+ type: vcType,
217
+ kid,
218
+ ...contentId !== void 0 ? { contentId } : {}
219
+ };
220
+ };
221
+ var decodeCredentialUnsafe = (token) => {
222
+ const parts = token.split(".");
223
+ if (parts.length !== 3) return null;
224
+ try {
225
+ const [headerB64, payloadB64] = parts;
226
+ const header = JSON.parse(new TextDecoder().decode(base64urlDecode(headerB64)));
227
+ const payload = JSON.parse(new TextDecoder().decode(base64urlDecode(payloadB64)));
228
+ const result = CredentialClaims.safeParse(payload);
229
+ if (!result.success) return null;
230
+ return { header, claims: result.data };
231
+ } catch {
232
+ return null;
233
+ }
234
+ };
235
+ var CredentialVerificationError = class extends Error {
236
+ constructor(message) {
237
+ super(message);
238
+ this.name = "CredentialVerificationError";
239
+ }
240
+ };
241
+
242
+ export {
243
+ VC_TYPE_CONTENT_WRITE,
244
+ VC_TYPE_CONTENT_READ,
245
+ DFOSCredentialType,
246
+ AuthTokenClaims,
247
+ ContentWriteSubject,
248
+ ContentReadSubject,
249
+ VCClaim,
250
+ CredentialClaims,
251
+ createAuthToken,
252
+ verifyAuthToken,
253
+ AuthTokenVerificationError,
254
+ createCredential,
255
+ verifyCredential,
256
+ decodeCredentialUnsafe,
257
+ CredentialVerificationError
258
+ };
@@ -1,3 +1,8 @@
1
+ import {
2
+ VC_TYPE_CONTENT_WRITE,
3
+ decodeCredentialUnsafe,
4
+ verifyCredential
5
+ } from "./chunk-CZSEEZLL.js";
1
6
  import {
2
7
  createJws,
3
8
  dagCborCanonicalEncode,
@@ -73,7 +78,9 @@ var ContentUpdate = z.strictObject({
73
78
  documentCID: CIDString.nullable(),
74
79
  baseDocumentCID: CIDString.nullable(),
75
80
  createdAt: Iso8601,
76
- note: z.string().max(MAX_NOTE).nullable()
81
+ note: z.string().max(MAX_NOTE).nullable(),
82
+ /** VC-JWT authorizing this operation when signer is not the chain creator */
83
+ authorization: z.string().optional()
77
84
  });
78
85
  var ContentDelete = z.strictObject({
79
86
  version: z.literal(1),
@@ -81,7 +88,9 @@ var ContentDelete = z.strictObject({
81
88
  did: z.string().max(MAX_DID),
82
89
  previousOperationCID: CIDString,
83
90
  createdAt: Iso8601,
84
- note: z.string().max(MAX_NOTE).nullable()
91
+ note: z.string().max(MAX_NOTE).nullable(),
92
+ /** VC-JWT authorizing this operation when signer is not the chain creator */
93
+ authorization: z.string().optional()
85
94
  });
86
95
  var ContentOperation = z.discriminatedUnion("type", [
87
96
  ContentCreate,
@@ -311,7 +320,8 @@ var verifyContentChain = async (input) => {
311
320
  isDeleted: false,
312
321
  currentDocumentCID: null,
313
322
  previousCID: null,
314
- lastCreatedAt: null
323
+ lastCreatedAt: null,
324
+ creatorDID: null
315
325
  };
316
326
  for (const [idx, jwsToken] of input.log.entries()) {
317
327
  const decoded = decodeJwsUnsafe(jwsToken);
@@ -354,6 +364,51 @@ var verifyContentChain = async (input) => {
354
364
  } catch {
355
365
  throw new Error(`log[${idx}]: invalid signature`);
356
366
  }
367
+ if (idx === 0) {
368
+ state.creatorDID = op.did;
369
+ } else if (op.did !== state.creatorDID && input.enforceAuthorization) {
370
+ const authorization = op.type !== "create" ? op.authorization : void 0;
371
+ if (!authorization) {
372
+ throw new Error(
373
+ `log[${idx}]: signer ${op.did} is not the chain creator \u2014 authorization VC required`
374
+ );
375
+ }
376
+ const vcDecoded = decodeCredentialUnsafe(authorization);
377
+ if (!vcDecoded) {
378
+ throw new Error(`log[${idx}]: failed to decode authorization VC`);
379
+ }
380
+ const vcKid = vcDecoded.header.kid;
381
+ if (!vcKid || !vcKid.includes("#")) {
382
+ throw new Error(`log[${idx}]: authorization VC kid must be a DID URL`);
383
+ }
384
+ let creatorPublicKey;
385
+ try {
386
+ creatorPublicKey = await input.resolveKey(vcKid);
387
+ } catch {
388
+ throw new Error(`log[${idx}]: cannot resolve creator key for authorization verification`);
389
+ }
390
+ const opCreatedAtUnix = Math.floor(new Date(op.createdAt).getTime() / 1e3);
391
+ try {
392
+ const credential = verifyCredential({
393
+ token: authorization,
394
+ publicKey: creatorPublicKey,
395
+ subject: op.did,
396
+ expectedType: VC_TYPE_CONTENT_WRITE,
397
+ currentTime: opCreatedAtUnix
398
+ });
399
+ if (credential.iss !== state.creatorDID) {
400
+ throw new Error("VC issuer is not the chain creator");
401
+ }
402
+ if (credential.contentId && credential.contentId !== state.contentId) {
403
+ throw new Error(
404
+ `VC contentId ${credential.contentId} does not match chain ${state.contentId}`
405
+ );
406
+ }
407
+ } catch (err) {
408
+ const message = err instanceof Error ? err.message : "unknown error";
409
+ throw new Error(`log[${idx}]: authorization verification failed: ${message}`);
410
+ }
411
+ }
357
412
  const encoded = await dagCborCanonicalEncode(op);
358
413
  const operationCID = encoded.cid.toString();
359
414
  if (!decoded.header.cid) {
@@ -388,7 +443,8 @@ var verifyContentChain = async (input) => {
388
443
  headCID: state.headCID,
389
444
  isDeleted: state.isDeleted,
390
445
  currentDocumentCID: state.currentDocumentCID,
391
- length: input.log.length
446
+ length: input.log.length,
447
+ creatorDID: state.creatorDID
392
448
  };
393
449
  };
394
450
 
@@ -0,0 +1,206 @@
1
+ import { z } from 'zod';
2
+
3
+ /** VC type for authorizing content chain writes (delegated operations) */
4
+ declare const VC_TYPE_CONTENT_WRITE = "DFOSContentWrite";
5
+ /** VC type for authorizing content plane reads (relay access) */
6
+ declare const VC_TYPE_CONTENT_READ = "DFOSContentRead";
7
+ /** All known DFOS VC types */
8
+ declare const DFOSCredentialType: z.ZodEnum<{
9
+ DFOSContentWrite: "DFOSContentWrite";
10
+ DFOSContentRead: "DFOSContentRead";
11
+ }>;
12
+ type DFOSCredentialType = z.infer<typeof DFOSCredentialType>;
13
+ /** Claims for a DID-signed auth token (relay AuthN) */
14
+ declare const AuthTokenClaims: z.ZodObject<{
15
+ /** Issuer — the DID proving identity */
16
+ iss: z.ZodString;
17
+ /** Subject — same as iss for auth tokens */
18
+ sub: z.ZodString;
19
+ /** Audience — target relay hostname (prevents cross-relay replay) */
20
+ aud: z.ZodString;
21
+ /** Expiration — unix seconds, short-lived (minutes) */
22
+ exp: z.ZodNumber;
23
+ /** Issued at — unix seconds */
24
+ iat: z.ZodNumber;
25
+ }, z.core.$strict>;
26
+ type AuthTokenClaims = z.infer<typeof AuthTokenClaims>;
27
+ /** Credential subject for content write authorization */
28
+ declare const ContentWriteSubject: z.ZodObject<{
29
+ /** Optional content chain narrowing — if absent, grants broad write access */
30
+ contentId: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strict>;
32
+ type ContentWriteSubject = z.infer<typeof ContentWriteSubject>;
33
+ /** Credential subject for content read authorization */
34
+ declare const ContentReadSubject: z.ZodObject<{
35
+ /** Optional content chain narrowing — if absent, grants broad read access */
36
+ contentId: z.ZodOptional<z.ZodString>;
37
+ }, z.core.$strict>;
38
+ type ContentReadSubject = z.infer<typeof ContentReadSubject>;
39
+ /** The `vc` claim in a VC-JWT payload */
40
+ declare const VCClaim: z.ZodObject<{
41
+ '@context': z.ZodTuple<[z.ZodLiteral<"https://www.w3.org/ns/credentials/v2">], null>;
42
+ type: z.ZodPipe<z.ZodTuple<[z.ZodLiteral<"VerifiableCredential">, z.ZodEnum<{
43
+ DFOSContentWrite: "DFOSContentWrite";
44
+ DFOSContentRead: "DFOSContentRead";
45
+ }>], null>, z.ZodTransform<[string, "DFOSContentWrite" | "DFOSContentRead"], ["VerifiableCredential", "DFOSContentWrite" | "DFOSContentRead"]>>;
46
+ credentialSubject: z.ZodUnion<readonly [z.ZodObject<{
47
+ /** Optional content chain narrowing — if absent, grants broad write access */
48
+ contentId: z.ZodOptional<z.ZodString>;
49
+ }, z.core.$strict>, z.ZodObject<{
50
+ /** Optional content chain narrowing — if absent, grants broad read access */
51
+ contentId: z.ZodOptional<z.ZodString>;
52
+ }, z.core.$strict>]>;
53
+ }, z.core.$strict>;
54
+ type VCClaim = z.infer<typeof VCClaim>;
55
+ /** Full VC-JWT payload claims */
56
+ declare const CredentialClaims: z.ZodObject<{
57
+ /** Issuer — the DID granting the credential */
58
+ iss: z.ZodString;
59
+ /** Subject — the DID receiving the credential */
60
+ sub: z.ZodString;
61
+ /** Expiration — unix seconds */
62
+ exp: z.ZodNumber;
63
+ /** Issued at — unix seconds */
64
+ iat: z.ZodNumber;
65
+ /** Verifiable credential claim */
66
+ vc: z.ZodObject<{
67
+ '@context': z.ZodTuple<[z.ZodLiteral<"https://www.w3.org/ns/credentials/v2">], null>;
68
+ type: z.ZodPipe<z.ZodTuple<[z.ZodLiteral<"VerifiableCredential">, z.ZodEnum<{
69
+ DFOSContentWrite: "DFOSContentWrite";
70
+ DFOSContentRead: "DFOSContentRead";
71
+ }>], null>, z.ZodTransform<[string, "DFOSContentWrite" | "DFOSContentRead"], ["VerifiableCredential", "DFOSContentWrite" | "DFOSContentRead"]>>;
72
+ credentialSubject: z.ZodUnion<readonly [z.ZodObject<{
73
+ /** Optional content chain narrowing — if absent, grants broad write access */
74
+ contentId: z.ZodOptional<z.ZodString>;
75
+ }, z.core.$strict>, z.ZodObject<{
76
+ /** Optional content chain narrowing — if absent, grants broad read access */
77
+ contentId: z.ZodOptional<z.ZodString>;
78
+ }, z.core.$strict>]>;
79
+ }, z.core.$strict>;
80
+ }, z.core.$strict>;
81
+ type CredentialClaims = z.infer<typeof CredentialClaims>;
82
+
83
+ interface AuthTokenCreateOptions {
84
+ /** The DID proving identity */
85
+ iss: string;
86
+ /** Target relay hostname (prevents cross-relay replay) */
87
+ aud: string;
88
+ /** Expiration — unix seconds */
89
+ exp: number;
90
+ /** kid — DID URL: "did:dfos:xxx#key_yyy" */
91
+ kid: string;
92
+ /** Issued-at override — unix seconds (defaults to Date.now()) */
93
+ iat?: number;
94
+ /** Signer function */
95
+ sign: (message: Uint8Array) => Promise<Uint8Array>;
96
+ }
97
+ interface AuthTokenVerifyOptions {
98
+ /** The JWT token string */
99
+ token: string;
100
+ /** Raw Ed25519 public key bytes (32 bytes) */
101
+ publicKey: Uint8Array;
102
+ /** Expected audience (relay hostname) */
103
+ audience: string;
104
+ /** Current time in seconds (defaults to Date.now() / 1000) */
105
+ currentTime?: number;
106
+ }
107
+ interface VerifiedAuthToken {
108
+ /** The DID that created the token */
109
+ iss: string;
110
+ /** The target relay */
111
+ aud: string;
112
+ /** Token expiration (unix seconds) */
113
+ exp: number;
114
+ /** kid from the JWT header */
115
+ kid: string;
116
+ }
117
+ /**
118
+ * Create a DID-signed auth token JWT for relay authentication
119
+ */
120
+ declare const createAuthToken: (options: AuthTokenCreateOptions) => Promise<string>;
121
+ /**
122
+ * Verify a DID-signed auth token JWT
123
+ *
124
+ * Checks signature, expiration, audience, and payload structure.
125
+ */
126
+ declare const verifyAuthToken: (options: AuthTokenVerifyOptions) => VerifiedAuthToken;
127
+ declare class AuthTokenVerificationError extends Error {
128
+ constructor(message: string);
129
+ }
130
+
131
+ interface CredentialCreateOptions {
132
+ /** The DID granting the credential (content creator/controller) */
133
+ iss: string;
134
+ /** The DID receiving the credential (collaborator/reader) */
135
+ sub: string;
136
+ /** Expiration — unix seconds */
137
+ exp: number;
138
+ /** kid — DID URL of the issuer: "did:dfos:xxx#key_yyy" */
139
+ kid: string;
140
+ /** Credential type */
141
+ type: DFOSCredentialType;
142
+ /** Optional content chain narrowing */
143
+ contentId?: string;
144
+ /** Issued-at override — unix seconds (defaults to Date.now()) */
145
+ iat?: number;
146
+ /** Signer function */
147
+ sign: (message: Uint8Array) => Promise<Uint8Array>;
148
+ }
149
+ interface CredentialVerifyOptions {
150
+ /** The VC-JWT token string */
151
+ token: string;
152
+ /** Raw Ed25519 public key bytes (32 bytes) of the issuer */
153
+ publicKey: Uint8Array;
154
+ /** Expected subject DID (optional — if provided, sub must match) */
155
+ subject?: string;
156
+ /** Expected credential type (optional — if provided, type must match) */
157
+ expectedType?: DFOSCredentialType;
158
+ /** Current time in seconds (defaults to Date.now() / 1000) */
159
+ currentTime?: number;
160
+ }
161
+ interface VerifiedCredential {
162
+ /** The DID that issued the credential */
163
+ iss: string;
164
+ /** The DID the credential was issued to */
165
+ sub: string;
166
+ /** Credential expiration (unix seconds) */
167
+ exp: number;
168
+ /** The DFOS credential type */
169
+ type: DFOSCredentialType;
170
+ /** kid from the JWT header */
171
+ kid: string;
172
+ /** Optional content chain narrowing */
173
+ contentId?: string;
174
+ }
175
+ /**
176
+ * Create a VC-JWT credential
177
+ *
178
+ * The credential is a JWT with `typ: "vc+jwt"` in the header and a `vc`
179
+ * claim in the payload following W3C VC Data Model v2.
180
+ */
181
+ declare const createCredential: (options: CredentialCreateOptions) => Promise<string>;
182
+ /**
183
+ * Verify a VC-JWT credential
184
+ *
185
+ * Checks signature, expiration, payload structure, and optionally subject
186
+ * and credential type.
187
+ */
188
+ declare const verifyCredential: (options: CredentialVerifyOptions) => VerifiedCredential;
189
+ /**
190
+ * Decode a VC-JWT credential without verifying the signature
191
+ *
192
+ * Returns null if the token is malformed or claims are invalid.
193
+ */
194
+ declare const decodeCredentialUnsafe: (token: string) => {
195
+ header: {
196
+ alg: string;
197
+ typ: string;
198
+ kid: string;
199
+ };
200
+ claims: CredentialClaims;
201
+ } | null;
202
+ declare class CredentialVerificationError extends Error {
203
+ constructor(message: string);
204
+ }
205
+
206
+ export { AuthTokenClaims, type AuthTokenCreateOptions, AuthTokenVerificationError, type AuthTokenVerifyOptions, ContentReadSubject, ContentWriteSubject, CredentialClaims, type CredentialCreateOptions, CredentialVerificationError, type CredentialVerifyOptions, DFOSCredentialType, VCClaim, VC_TYPE_CONTENT_READ, VC_TYPE_CONTENT_WRITE, type VerifiedAuthToken, type VerifiedCredential, createAuthToken, createCredential, decodeCredentialUnsafe, verifyAuthToken, verifyCredential };
@@ -0,0 +1,35 @@
1
+ import {
2
+ AuthTokenClaims,
3
+ AuthTokenVerificationError,
4
+ ContentReadSubject,
5
+ ContentWriteSubject,
6
+ CredentialClaims,
7
+ CredentialVerificationError,
8
+ DFOSCredentialType,
9
+ VCClaim,
10
+ VC_TYPE_CONTENT_READ,
11
+ VC_TYPE_CONTENT_WRITE,
12
+ createAuthToken,
13
+ createCredential,
14
+ decodeCredentialUnsafe,
15
+ verifyAuthToken,
16
+ verifyCredential
17
+ } from "../chunk-CZSEEZLL.js";
18
+ import "../chunk-ZXXP5W5N.js";
19
+ export {
20
+ AuthTokenClaims,
21
+ AuthTokenVerificationError,
22
+ ContentReadSubject,
23
+ ContentWriteSubject,
24
+ CredentialClaims,
25
+ CredentialVerificationError,
26
+ DFOSCredentialType,
27
+ VCClaim,
28
+ VC_TYPE_CONTENT_READ,
29
+ VC_TYPE_CONTENT_WRITE,
30
+ createAuthToken,
31
+ createCredential,
32
+ decodeCredentialUnsafe,
33
+ verifyAuthToken,
34
+ verifyCredential
35
+ };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
2
2
  export { BeaconPayload, ContentOperation, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, MultikeyPublicKey, Signer, VerifiedBeacon, VerifiedBeaconCountersignature, VerifiedContentChain, VerifiedCountersignature, VerifiedIdentity, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, signBeacon, signContentOperation, signCountersignature, signIdentityOperation, verifyBeacon, verifyBeaconCountersignature, verifyContentChain, verifyCountersignature, verifyIdentityChain } from './chain/index.js';
3
3
  export { MerkleProof, buildMerkleTree, generateMerkleProof, hashLeaf, hexToBytes, verifyMerkleProof } from './merkle/index.js';
4
+ export { AuthTokenClaims, AuthTokenCreateOptions, AuthTokenVerificationError, AuthTokenVerifyOptions, ContentReadSubject, ContentWriteSubject, CredentialClaims, CredentialCreateOptions, CredentialVerificationError, CredentialVerifyOptions, DFOSCredentialType, VCClaim, VC_TYPE_CONTENT_READ, VC_TYPE_CONTENT_WRITE, VerifiedAuthToken, VerifiedCredential, createAuthToken, createCredential, decodeCredentialUnsafe, verifyAuthToken, verifyCredential } from './credentials/index.js';
4
5
  import 'multiformats';
5
6
  import 'multiformats/cid';
6
7
  import 'zod';
package/dist/index.js CHANGED
@@ -19,7 +19,31 @@ import {
19
19
  verifyContentChain,
20
20
  verifyCountersignature,
21
21
  verifyIdentityChain
22
- } from "./chunk-ASGEXSVT.js";
22
+ } from "./chunk-GEVJ3SEV.js";
23
+ import {
24
+ buildMerkleTree,
25
+ generateMerkleProof,
26
+ hashLeaf,
27
+ hexToBytes,
28
+ verifyMerkleProof
29
+ } from "./chunk-E5CFQG2B.js";
30
+ import {
31
+ AuthTokenClaims,
32
+ AuthTokenVerificationError,
33
+ ContentReadSubject,
34
+ ContentWriteSubject,
35
+ CredentialClaims,
36
+ CredentialVerificationError,
37
+ DFOSCredentialType,
38
+ VCClaim,
39
+ VC_TYPE_CONTENT_READ,
40
+ VC_TYPE_CONTENT_WRITE,
41
+ createAuthToken,
42
+ createCredential,
43
+ decodeCredentialUnsafe,
44
+ verifyAuthToken,
45
+ verifyCredential
46
+ } from "./chunk-CZSEEZLL.js";
23
47
  import {
24
48
  JwsVerificationError,
25
49
  JwtVerificationError,
@@ -43,30 +67,36 @@ import {
43
67
  verifyJws,
44
68
  verifyJwt
45
69
  } from "./chunk-ZXXP5W5N.js";
46
- import {
47
- buildMerkleTree,
48
- generateMerkleProof,
49
- hashLeaf,
50
- hexToBytes,
51
- verifyMerkleProof
52
- } from "./chunk-E5CFQG2B.js";
53
70
  export {
71
+ AuthTokenClaims,
72
+ AuthTokenVerificationError,
54
73
  BeaconPayload,
55
74
  ContentOperation,
75
+ ContentReadSubject,
76
+ ContentWriteSubject,
77
+ CredentialClaims,
78
+ CredentialVerificationError,
79
+ DFOSCredentialType,
56
80
  ED25519_PRIV_MULTICODEC,
57
81
  ED25519_PUB_MULTICODEC,
58
82
  IdentityOperation,
59
83
  JwsVerificationError,
60
84
  JwtVerificationError,
61
85
  MultikeyPublicKey,
86
+ VCClaim,
87
+ VC_TYPE_CONTENT_READ,
88
+ VC_TYPE_CONTENT_WRITE,
62
89
  VerifiedIdentity,
63
90
  base64urlDecode,
64
91
  base64urlEncode,
65
92
  buildMerkleTree,
93
+ createAuthToken,
94
+ createCredential,
66
95
  createJws,
67
96
  createJwt,
68
97
  createNewEd25519Keypair,
69
98
  dagCborCanonicalEncode,
99
+ decodeCredentialUnsafe,
70
100
  decodeJwsUnsafe,
71
101
  decodeJwtUnsafe,
72
102
  decodeMultikey,
@@ -89,10 +119,12 @@ export {
89
119
  signCountersignature,
90
120
  signIdentityOperation,
91
121
  signPayloadEd25519,
122
+ verifyAuthToken,
92
123
  verifyBeacon,
93
124
  verifyBeaconCountersignature,
94
125
  verifyContentChain,
95
126
  verifyCountersignature,
127
+ verifyCredential,
96
128
  verifyIdentityChain,
97
129
  verifyJws,
98
130
  verifyJwt,