@daena/core 0.1.0-alpha.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.
package/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # @daena/core
2
+
3
+ Core types, schema validation, and document utilities for the Daena Protocol.
4
+
5
+ This package is the foundation every other reference package depends on. It contains:
6
+
7
+ - TypeScript types for Daena documents, facts, capabilities, and render hints
8
+ - JSON Schema validators for the on-the-wire shapes defined in [SPEC.md](https://github.com/daena-protocol/spec/blob/main/SPEC.md)
9
+ - Canonical serialization helpers required for stable signing
10
+
11
+ ## Status
12
+
13
+ Pre-alpha. Interfaces will change as the spec evolves toward v1.
14
+
15
+ ## License
16
+
17
+ [Apache-2.0](../../LICENSE).
@@ -0,0 +1,527 @@
1
+ import { z, ZodError } from 'zod';
2
+
3
+ /**
4
+ * Daena Protocol v0 — TypeScript types
5
+ *
6
+ * Derived from SPEC.md sections 2-5. These types track the editor's draft
7
+ * and will evolve until v1.0.
8
+ */
9
+ /** A cryptographic attestation by a publisher. */
10
+ interface Signature {
11
+ /** Algorithm identifier, e.g. "ed25519". */
12
+ algorithm: string;
13
+ /** Base64-encoded signature value. */
14
+ value: string;
15
+ /** DID URL identifying the key that produced the signature. */
16
+ keyId: string;
17
+ }
18
+ /** A typed, dated, signed statement made by a publisher about a subject. */
19
+ interface Fact {
20
+ /** Stable identifier for this fact within the document. */
21
+ id: string;
22
+ /** URI identifying the vocabulary under which this fact is interpreted. */
23
+ type: string;
24
+ /** The fact's value. May be a primitive, object, or array. */
25
+ value: unknown;
26
+ /** ISO 8601 timestamp of when the fact was last asserted. */
27
+ asOf: string;
28
+ /** Optional per-fact signature. If absent, the document-level signature attests this fact. */
29
+ signature?: Signature;
30
+ }
31
+ /** Typed parameter specification for a capability. */
32
+ interface CapabilityParameter {
33
+ type: "string" | "integer" | "number" | "boolean" | "datetime" | "phone" | "email";
34
+ required: boolean;
35
+ min?: number;
36
+ max?: number;
37
+ pattern?: string;
38
+ }
39
+ /** An action a publisher offers to agents. */
40
+ interface Capability {
41
+ /** Stable identifier for this capability within the document. */
42
+ id: string;
43
+ /** Human-readable label for the action. */
44
+ name: string;
45
+ /** URI identifying the capability vocabulary. */
46
+ type: string;
47
+ /** Typed parameter specifications keyed by parameter name. */
48
+ parameters: Record<string, CapabilityParameter>;
49
+ /** HTTPS endpoint where ACT requests are sent. */
50
+ endpoint: string;
51
+ /** Authentication mode required to invoke this capability. */
52
+ auth: "none" | "bearer" | "did";
53
+ /** Optional payment requirement. */
54
+ price?: {
55
+ amount: number;
56
+ currency: string;
57
+ };
58
+ }
59
+ /** Optional metadata that guides how a renderer produces a human view. */
60
+ interface RenderHints {
61
+ /** Title shown at the top of the rendered view. */
62
+ title?: string;
63
+ /** Ordered list of fact IDs to feature prominently. */
64
+ primary?: string[];
65
+ /** Ordered list of capability IDs to surface as primary actions. */
66
+ callsToAction?: string[];
67
+ /** Optional theming. */
68
+ theme?: {
69
+ accent?: string;
70
+ };
71
+ }
72
+ /** A complete Daena document — the atomic unit of publication. */
73
+ interface DaenaDocument {
74
+ /** Protocol version. */
75
+ daena: "0";
76
+ /** Publisher identity as a Decentralized Identifier. */
77
+ publisher: string;
78
+ /** Signed statements made by the publisher. */
79
+ facts: Fact[];
80
+ /** Actions the publisher offers to agents. */
81
+ capabilities: Capability[];
82
+ /** Optional rendering metadata. */
83
+ render?: RenderHints;
84
+ /** Document-level signature. */
85
+ signature: Signature;
86
+ }
87
+
88
+ declare const SignatureSchema: z.ZodObject<{
89
+ algorithm: z.ZodString;
90
+ value: z.ZodString;
91
+ keyId: z.ZodString;
92
+ }, "strip", z.ZodTypeAny, {
93
+ algorithm: string;
94
+ value: string;
95
+ keyId: string;
96
+ }, {
97
+ algorithm: string;
98
+ value: string;
99
+ keyId: string;
100
+ }>;
101
+ declare const CapabilityParameterSchema: z.ZodObject<{
102
+ type: z.ZodEnum<["string", "integer", "number", "boolean", "datetime", "phone", "email"]>;
103
+ required: z.ZodBoolean;
104
+ min: z.ZodOptional<z.ZodNumber>;
105
+ max: z.ZodOptional<z.ZodNumber>;
106
+ pattern: z.ZodOptional<z.ZodString>;
107
+ }, "strip", z.ZodTypeAny, {
108
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
109
+ required: boolean;
110
+ min?: number | undefined;
111
+ max?: number | undefined;
112
+ pattern?: string | undefined;
113
+ }, {
114
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
115
+ required: boolean;
116
+ min?: number | undefined;
117
+ max?: number | undefined;
118
+ pattern?: string | undefined;
119
+ }>;
120
+ declare const CapabilitySchema: z.ZodObject<{
121
+ id: z.ZodString;
122
+ name: z.ZodString;
123
+ type: z.ZodString;
124
+ parameters: z.ZodRecord<z.ZodString, z.ZodObject<{
125
+ type: z.ZodEnum<["string", "integer", "number", "boolean", "datetime", "phone", "email"]>;
126
+ required: z.ZodBoolean;
127
+ min: z.ZodOptional<z.ZodNumber>;
128
+ max: z.ZodOptional<z.ZodNumber>;
129
+ pattern: z.ZodOptional<z.ZodString>;
130
+ }, "strip", z.ZodTypeAny, {
131
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
132
+ required: boolean;
133
+ min?: number | undefined;
134
+ max?: number | undefined;
135
+ pattern?: string | undefined;
136
+ }, {
137
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
138
+ required: boolean;
139
+ min?: number | undefined;
140
+ max?: number | undefined;
141
+ pattern?: string | undefined;
142
+ }>>;
143
+ endpoint: z.ZodString;
144
+ auth: z.ZodEnum<["none", "bearer", "did"]>;
145
+ price: z.ZodOptional<z.ZodObject<{
146
+ amount: z.ZodNumber;
147
+ currency: z.ZodString;
148
+ }, "strip", z.ZodTypeAny, {
149
+ amount: number;
150
+ currency: string;
151
+ }, {
152
+ amount: number;
153
+ currency: string;
154
+ }>>;
155
+ }, "strip", z.ZodTypeAny, {
156
+ type: string;
157
+ id: string;
158
+ name: string;
159
+ parameters: Record<string, {
160
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
161
+ required: boolean;
162
+ min?: number | undefined;
163
+ max?: number | undefined;
164
+ pattern?: string | undefined;
165
+ }>;
166
+ endpoint: string;
167
+ auth: "none" | "bearer" | "did";
168
+ price?: {
169
+ amount: number;
170
+ currency: string;
171
+ } | undefined;
172
+ }, {
173
+ type: string;
174
+ id: string;
175
+ name: string;
176
+ parameters: Record<string, {
177
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
178
+ required: boolean;
179
+ min?: number | undefined;
180
+ max?: number | undefined;
181
+ pattern?: string | undefined;
182
+ }>;
183
+ endpoint: string;
184
+ auth: "none" | "bearer" | "did";
185
+ price?: {
186
+ amount: number;
187
+ currency: string;
188
+ } | undefined;
189
+ }>;
190
+ declare const FactSchema: z.ZodObject<{
191
+ id: z.ZodString;
192
+ type: z.ZodString;
193
+ value: z.ZodUnknown;
194
+ asOf: z.ZodString;
195
+ signature: z.ZodOptional<z.ZodObject<{
196
+ algorithm: z.ZodString;
197
+ value: z.ZodString;
198
+ keyId: z.ZodString;
199
+ }, "strip", z.ZodTypeAny, {
200
+ algorithm: string;
201
+ value: string;
202
+ keyId: string;
203
+ }, {
204
+ algorithm: string;
205
+ value: string;
206
+ keyId: string;
207
+ }>>;
208
+ }, "strip", z.ZodTypeAny, {
209
+ type: string;
210
+ id: string;
211
+ asOf: string;
212
+ value?: unknown;
213
+ signature?: {
214
+ algorithm: string;
215
+ value: string;
216
+ keyId: string;
217
+ } | undefined;
218
+ }, {
219
+ type: string;
220
+ id: string;
221
+ asOf: string;
222
+ value?: unknown;
223
+ signature?: {
224
+ algorithm: string;
225
+ value: string;
226
+ keyId: string;
227
+ } | undefined;
228
+ }>;
229
+ declare const RenderHintsSchema: z.ZodObject<{
230
+ title: z.ZodOptional<z.ZodString>;
231
+ primary: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
232
+ callsToAction: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
233
+ theme: z.ZodOptional<z.ZodObject<{
234
+ accent: z.ZodOptional<z.ZodString>;
235
+ }, "strip", z.ZodTypeAny, {
236
+ accent?: string | undefined;
237
+ }, {
238
+ accent?: string | undefined;
239
+ }>>;
240
+ }, "strip", z.ZodTypeAny, {
241
+ title?: string | undefined;
242
+ primary?: string[] | undefined;
243
+ callsToAction?: string[] | undefined;
244
+ theme?: {
245
+ accent?: string | undefined;
246
+ } | undefined;
247
+ }, {
248
+ title?: string | undefined;
249
+ primary?: string[] | undefined;
250
+ callsToAction?: string[] | undefined;
251
+ theme?: {
252
+ accent?: string | undefined;
253
+ } | undefined;
254
+ }>;
255
+ declare const DaenaDocumentSchema: z.ZodObject<{
256
+ daena: z.ZodLiteral<"0">;
257
+ publisher: z.ZodString;
258
+ facts: z.ZodArray<z.ZodObject<{
259
+ id: z.ZodString;
260
+ type: z.ZodString;
261
+ value: z.ZodUnknown;
262
+ asOf: z.ZodString;
263
+ signature: z.ZodOptional<z.ZodObject<{
264
+ algorithm: z.ZodString;
265
+ value: z.ZodString;
266
+ keyId: z.ZodString;
267
+ }, "strip", z.ZodTypeAny, {
268
+ algorithm: string;
269
+ value: string;
270
+ keyId: string;
271
+ }, {
272
+ algorithm: string;
273
+ value: string;
274
+ keyId: string;
275
+ }>>;
276
+ }, "strip", z.ZodTypeAny, {
277
+ type: string;
278
+ id: string;
279
+ asOf: string;
280
+ value?: unknown;
281
+ signature?: {
282
+ algorithm: string;
283
+ value: string;
284
+ keyId: string;
285
+ } | undefined;
286
+ }, {
287
+ type: string;
288
+ id: string;
289
+ asOf: string;
290
+ value?: unknown;
291
+ signature?: {
292
+ algorithm: string;
293
+ value: string;
294
+ keyId: string;
295
+ } | undefined;
296
+ }>, "many">;
297
+ capabilities: z.ZodArray<z.ZodObject<{
298
+ id: z.ZodString;
299
+ name: z.ZodString;
300
+ type: z.ZodString;
301
+ parameters: z.ZodRecord<z.ZodString, z.ZodObject<{
302
+ type: z.ZodEnum<["string", "integer", "number", "boolean", "datetime", "phone", "email"]>;
303
+ required: z.ZodBoolean;
304
+ min: z.ZodOptional<z.ZodNumber>;
305
+ max: z.ZodOptional<z.ZodNumber>;
306
+ pattern: z.ZodOptional<z.ZodString>;
307
+ }, "strip", z.ZodTypeAny, {
308
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
309
+ required: boolean;
310
+ min?: number | undefined;
311
+ max?: number | undefined;
312
+ pattern?: string | undefined;
313
+ }, {
314
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
315
+ required: boolean;
316
+ min?: number | undefined;
317
+ max?: number | undefined;
318
+ pattern?: string | undefined;
319
+ }>>;
320
+ endpoint: z.ZodString;
321
+ auth: z.ZodEnum<["none", "bearer", "did"]>;
322
+ price: z.ZodOptional<z.ZodObject<{
323
+ amount: z.ZodNumber;
324
+ currency: z.ZodString;
325
+ }, "strip", z.ZodTypeAny, {
326
+ amount: number;
327
+ currency: string;
328
+ }, {
329
+ amount: number;
330
+ currency: string;
331
+ }>>;
332
+ }, "strip", z.ZodTypeAny, {
333
+ type: string;
334
+ id: string;
335
+ name: string;
336
+ parameters: Record<string, {
337
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
338
+ required: boolean;
339
+ min?: number | undefined;
340
+ max?: number | undefined;
341
+ pattern?: string | undefined;
342
+ }>;
343
+ endpoint: string;
344
+ auth: "none" | "bearer" | "did";
345
+ price?: {
346
+ amount: number;
347
+ currency: string;
348
+ } | undefined;
349
+ }, {
350
+ type: string;
351
+ id: string;
352
+ name: string;
353
+ parameters: Record<string, {
354
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
355
+ required: boolean;
356
+ min?: number | undefined;
357
+ max?: number | undefined;
358
+ pattern?: string | undefined;
359
+ }>;
360
+ endpoint: string;
361
+ auth: "none" | "bearer" | "did";
362
+ price?: {
363
+ amount: number;
364
+ currency: string;
365
+ } | undefined;
366
+ }>, "many">;
367
+ render: z.ZodOptional<z.ZodObject<{
368
+ title: z.ZodOptional<z.ZodString>;
369
+ primary: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
370
+ callsToAction: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
371
+ theme: z.ZodOptional<z.ZodObject<{
372
+ accent: z.ZodOptional<z.ZodString>;
373
+ }, "strip", z.ZodTypeAny, {
374
+ accent?: string | undefined;
375
+ }, {
376
+ accent?: string | undefined;
377
+ }>>;
378
+ }, "strip", z.ZodTypeAny, {
379
+ title?: string | undefined;
380
+ primary?: string[] | undefined;
381
+ callsToAction?: string[] | undefined;
382
+ theme?: {
383
+ accent?: string | undefined;
384
+ } | undefined;
385
+ }, {
386
+ title?: string | undefined;
387
+ primary?: string[] | undefined;
388
+ callsToAction?: string[] | undefined;
389
+ theme?: {
390
+ accent?: string | undefined;
391
+ } | undefined;
392
+ }>>;
393
+ signature: z.ZodObject<{
394
+ algorithm: z.ZodString;
395
+ value: z.ZodString;
396
+ keyId: z.ZodString;
397
+ }, "strip", z.ZodTypeAny, {
398
+ algorithm: string;
399
+ value: string;
400
+ keyId: string;
401
+ }, {
402
+ algorithm: string;
403
+ value: string;
404
+ keyId: string;
405
+ }>;
406
+ }, "strip", z.ZodTypeAny, {
407
+ signature: {
408
+ algorithm: string;
409
+ value: string;
410
+ keyId: string;
411
+ };
412
+ daena: "0";
413
+ publisher: string;
414
+ facts: {
415
+ type: string;
416
+ id: string;
417
+ asOf: string;
418
+ value?: unknown;
419
+ signature?: {
420
+ algorithm: string;
421
+ value: string;
422
+ keyId: string;
423
+ } | undefined;
424
+ }[];
425
+ capabilities: {
426
+ type: string;
427
+ id: string;
428
+ name: string;
429
+ parameters: Record<string, {
430
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
431
+ required: boolean;
432
+ min?: number | undefined;
433
+ max?: number | undefined;
434
+ pattern?: string | undefined;
435
+ }>;
436
+ endpoint: string;
437
+ auth: "none" | "bearer" | "did";
438
+ price?: {
439
+ amount: number;
440
+ currency: string;
441
+ } | undefined;
442
+ }[];
443
+ render?: {
444
+ title?: string | undefined;
445
+ primary?: string[] | undefined;
446
+ callsToAction?: string[] | undefined;
447
+ theme?: {
448
+ accent?: string | undefined;
449
+ } | undefined;
450
+ } | undefined;
451
+ }, {
452
+ signature: {
453
+ algorithm: string;
454
+ value: string;
455
+ keyId: string;
456
+ };
457
+ daena: "0";
458
+ publisher: string;
459
+ facts: {
460
+ type: string;
461
+ id: string;
462
+ asOf: string;
463
+ value?: unknown;
464
+ signature?: {
465
+ algorithm: string;
466
+ value: string;
467
+ keyId: string;
468
+ } | undefined;
469
+ }[];
470
+ capabilities: {
471
+ type: string;
472
+ id: string;
473
+ name: string;
474
+ parameters: Record<string, {
475
+ type: "string" | "number" | "boolean" | "integer" | "datetime" | "phone" | "email";
476
+ required: boolean;
477
+ min?: number | undefined;
478
+ max?: number | undefined;
479
+ pattern?: string | undefined;
480
+ }>;
481
+ endpoint: string;
482
+ auth: "none" | "bearer" | "did";
483
+ price?: {
484
+ amount: number;
485
+ currency: string;
486
+ } | undefined;
487
+ }[];
488
+ render?: {
489
+ title?: string | undefined;
490
+ primary?: string[] | undefined;
491
+ callsToAction?: string[] | undefined;
492
+ theme?: {
493
+ accent?: string | undefined;
494
+ } | undefined;
495
+ } | undefined;
496
+ }>;
497
+
498
+ interface DaenaIssue {
499
+ path: string;
500
+ message: string;
501
+ }
502
+ declare class DaenaParseError extends Error {
503
+ readonly issues: DaenaIssue[];
504
+ constructor(zodError: ZodError);
505
+ }
506
+
507
+ /**
508
+ * Parse and validate a Daena document.
509
+ *
510
+ * Accepts either a JSON string or an already-parsed value.
511
+ * Throws DaenaParseError if the input fails v0 schema validation.
512
+ */
513
+ declare function parse(input: string | unknown): DaenaDocument;
514
+ /**
515
+ * Non-throwing variant of parse(). Returns a result object so callers can
516
+ * branch without try/catch.
517
+ */
518
+ type ParseResult = {
519
+ ok: true;
520
+ doc: DaenaDocument;
521
+ } | {
522
+ ok: false;
523
+ error: DaenaParseError;
524
+ };
525
+ declare function tryParse(input: string | unknown): ParseResult;
526
+
527
+ export { type Capability, type CapabilityParameter, CapabilityParameterSchema, CapabilitySchema, type DaenaDocument, DaenaDocumentSchema, type DaenaIssue, DaenaParseError, type Fact, FactSchema, type ParseResult, type RenderHints, RenderHintsSchema, type Signature, SignatureSchema, parse, tryParse };
package/dist/index.js ADDED
@@ -0,0 +1,102 @@
1
+ // src/schema.ts
2
+ import { z } from "zod";
3
+ var SignatureSchema = z.object({
4
+ algorithm: z.string().min(1),
5
+ value: z.string().min(1),
6
+ keyId: z.string().min(1)
7
+ });
8
+ var CapabilityParameterSchema = z.object({
9
+ type: z.enum([
10
+ "string",
11
+ "integer",
12
+ "number",
13
+ "boolean",
14
+ "datetime",
15
+ "phone",
16
+ "email"
17
+ ]),
18
+ required: z.boolean(),
19
+ min: z.number().optional(),
20
+ max: z.number().optional(),
21
+ pattern: z.string().optional()
22
+ });
23
+ var CapabilitySchema = z.object({
24
+ id: z.string().min(1),
25
+ name: z.string().min(1),
26
+ type: z.string().url(),
27
+ parameters: z.record(CapabilityParameterSchema),
28
+ endpoint: z.string().url(),
29
+ auth: z.enum(["none", "bearer", "did"]),
30
+ price: z.object({
31
+ amount: z.number(),
32
+ currency: z.string().length(3)
33
+ }).optional()
34
+ });
35
+ var FactSchema = z.object({
36
+ id: z.string().min(1),
37
+ type: z.string().url(),
38
+ value: z.unknown(),
39
+ asOf: z.string().datetime(),
40
+ signature: SignatureSchema.optional()
41
+ });
42
+ var RenderHintsSchema = z.object({
43
+ title: z.string().optional(),
44
+ primary: z.array(z.string()).optional(),
45
+ callsToAction: z.array(z.string()).optional(),
46
+ theme: z.object({
47
+ accent: z.string().optional()
48
+ }).optional()
49
+ });
50
+ var DaenaDocumentSchema = z.object({
51
+ daena: z.literal("0"),
52
+ publisher: z.string().min(1),
53
+ facts: z.array(FactSchema),
54
+ capabilities: z.array(CapabilitySchema),
55
+ render: RenderHintsSchema.optional(),
56
+ signature: SignatureSchema
57
+ });
58
+
59
+ // src/errors.ts
60
+ var DaenaParseError = class extends Error {
61
+ issues;
62
+ constructor(zodError) {
63
+ const issues = zodError.errors.map((e) => ({
64
+ path: e.path.join(".") || "(root)",
65
+ message: e.message
66
+ }));
67
+ const summary = issues.slice(0, 3).map((i) => `${i.path}: ${i.message}`).join("; ");
68
+ const tail = issues.length > 3 ? ` (+${issues.length - 3} more)` : "";
69
+ super(`Invalid Daena document \u2014 ${summary}${tail}`);
70
+ this.name = "DaenaParseError";
71
+ this.issues = issues;
72
+ }
73
+ };
74
+
75
+ // src/parse.ts
76
+ function parse(input) {
77
+ const raw = typeof input === "string" ? JSON.parse(input) : input;
78
+ const result = DaenaDocumentSchema.safeParse(raw);
79
+ if (!result.success) {
80
+ throw new DaenaParseError(result.error);
81
+ }
82
+ return result.data;
83
+ }
84
+ function tryParse(input) {
85
+ try {
86
+ return { ok: true, doc: parse(input) };
87
+ } catch (e) {
88
+ if (e instanceof DaenaParseError) return { ok: false, error: e };
89
+ throw e;
90
+ }
91
+ }
92
+ export {
93
+ CapabilityParameterSchema,
94
+ CapabilitySchema,
95
+ DaenaDocumentSchema,
96
+ DaenaParseError,
97
+ FactSchema,
98
+ RenderHintsSchema,
99
+ SignatureSchema,
100
+ parse,
101
+ tryParse
102
+ };
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@daena/core",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Core types and validation for the Daena Protocol",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": ["src", "dist"],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/daena-protocol/daena.git",
19
+ "directory": "packages/core"
20
+ },
21
+ "homepage": "https://daena-protocol.org",
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "scripts": {
26
+ "build": "tsup src/index.ts --format esm --dts --clean",
27
+ "test": "vitest run",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "dependencies": {
31
+ "zod": "^3.23.0"
32
+ }
33
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,25 @@
1
+ import type { ZodError } from "zod";
2
+
3
+ export interface DaenaIssue {
4
+ path: string;
5
+ message: string;
6
+ }
7
+
8
+ export class DaenaParseError extends Error {
9
+ readonly issues: DaenaIssue[];
10
+
11
+ constructor(zodError: ZodError) {
12
+ const issues: DaenaIssue[] = zodError.errors.map((e) => ({
13
+ path: e.path.join(".") || "(root)",
14
+ message: e.message
15
+ }));
16
+ const summary = issues
17
+ .slice(0, 3)
18
+ .map((i) => `${i.path}: ${i.message}`)
19
+ .join("; ");
20
+ const tail = issues.length > 3 ? ` (+${issues.length - 3} more)` : "";
21
+ super(`Invalid Daena document — ${summary}${tail}`);
22
+ this.name = "DaenaParseError";
23
+ this.issues = issues;
24
+ }
25
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./schema.js";
3
+ export * from "./parse.js";
4
+ export * from "./errors.js";
package/src/parse.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { DaenaDocumentSchema } from "./schema.js";
2
+ import { DaenaParseError } from "./errors.js";
3
+ import type { DaenaDocument } from "./types.js";
4
+
5
+ /**
6
+ * Parse and validate a Daena document.
7
+ *
8
+ * Accepts either a JSON string or an already-parsed value.
9
+ * Throws DaenaParseError if the input fails v0 schema validation.
10
+ */
11
+ export function parse(input: string | unknown): DaenaDocument {
12
+ const raw = typeof input === "string" ? JSON.parse(input) : input;
13
+ const result = DaenaDocumentSchema.safeParse(raw);
14
+ if (!result.success) {
15
+ throw new DaenaParseError(result.error);
16
+ }
17
+ return result.data as DaenaDocument;
18
+ }
19
+
20
+ /**
21
+ * Non-throwing variant of parse(). Returns a result object so callers can
22
+ * branch without try/catch.
23
+ */
24
+ export type ParseResult =
25
+ | { ok: true; doc: DaenaDocument }
26
+ | { ok: false; error: DaenaParseError };
27
+
28
+ export function tryParse(input: string | unknown): ParseResult {
29
+ try {
30
+ return { ok: true, doc: parse(input) };
31
+ } catch (e) {
32
+ if (e instanceof DaenaParseError) return { ok: false, error: e };
33
+ throw e;
34
+ }
35
+ }
package/src/schema.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+
3
+ export const SignatureSchema = z.object({
4
+ algorithm: z.string().min(1),
5
+ value: z.string().min(1),
6
+ keyId: z.string().min(1)
7
+ });
8
+
9
+ export const CapabilityParameterSchema = z.object({
10
+ type: z.enum([
11
+ "string",
12
+ "integer",
13
+ "number",
14
+ "boolean",
15
+ "datetime",
16
+ "phone",
17
+ "email"
18
+ ]),
19
+ required: z.boolean(),
20
+ min: z.number().optional(),
21
+ max: z.number().optional(),
22
+ pattern: z.string().optional()
23
+ });
24
+
25
+ export const CapabilitySchema = z.object({
26
+ id: z.string().min(1),
27
+ name: z.string().min(1),
28
+ type: z.string().url(),
29
+ parameters: z.record(CapabilityParameterSchema),
30
+ endpoint: z.string().url(),
31
+ auth: z.enum(["none", "bearer", "did"]),
32
+ price: z
33
+ .object({
34
+ amount: z.number(),
35
+ currency: z.string().length(3)
36
+ })
37
+ .optional()
38
+ });
39
+
40
+ export const FactSchema = z.object({
41
+ id: z.string().min(1),
42
+ type: z.string().url(),
43
+ value: z.unknown(),
44
+ asOf: z.string().datetime(),
45
+ signature: SignatureSchema.optional()
46
+ });
47
+
48
+ export const RenderHintsSchema = z.object({
49
+ title: z.string().optional(),
50
+ primary: z.array(z.string()).optional(),
51
+ callsToAction: z.array(z.string()).optional(),
52
+ theme: z
53
+ .object({
54
+ accent: z.string().optional()
55
+ })
56
+ .optional()
57
+ });
58
+
59
+ export const DaenaDocumentSchema = z.object({
60
+ daena: z.literal("0"),
61
+ publisher: z.string().min(1),
62
+ facts: z.array(FactSchema),
63
+ capabilities: z.array(CapabilitySchema),
64
+ render: RenderHintsSchema.optional(),
65
+ signature: SignatureSchema
66
+ });
package/src/types.ts ADDED
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Daena Protocol v0 — TypeScript types
3
+ *
4
+ * Derived from SPEC.md sections 2-5. These types track the editor's draft
5
+ * and will evolve until v1.0.
6
+ */
7
+
8
+ /** A cryptographic attestation by a publisher. */
9
+ export interface Signature {
10
+ /** Algorithm identifier, e.g. "ed25519". */
11
+ algorithm: string;
12
+ /** Base64-encoded signature value. */
13
+ value: string;
14
+ /** DID URL identifying the key that produced the signature. */
15
+ keyId: string;
16
+ }
17
+
18
+ /** A typed, dated, signed statement made by a publisher about a subject. */
19
+ export interface Fact {
20
+ /** Stable identifier for this fact within the document. */
21
+ id: string;
22
+ /** URI identifying the vocabulary under which this fact is interpreted. */
23
+ type: string;
24
+ /** The fact's value. May be a primitive, object, or array. */
25
+ value: unknown;
26
+ /** ISO 8601 timestamp of when the fact was last asserted. */
27
+ asOf: string;
28
+ /** Optional per-fact signature. If absent, the document-level signature attests this fact. */
29
+ signature?: Signature;
30
+ }
31
+
32
+ /** Typed parameter specification for a capability. */
33
+ export interface CapabilityParameter {
34
+ type: "string" | "integer" | "number" | "boolean" | "datetime" | "phone" | "email";
35
+ required: boolean;
36
+ min?: number;
37
+ max?: number;
38
+ pattern?: string;
39
+ }
40
+
41
+ /** An action a publisher offers to agents. */
42
+ export interface Capability {
43
+ /** Stable identifier for this capability within the document. */
44
+ id: string;
45
+ /** Human-readable label for the action. */
46
+ name: string;
47
+ /** URI identifying the capability vocabulary. */
48
+ type: string;
49
+ /** Typed parameter specifications keyed by parameter name. */
50
+ parameters: Record<string, CapabilityParameter>;
51
+ /** HTTPS endpoint where ACT requests are sent. */
52
+ endpoint: string;
53
+ /** Authentication mode required to invoke this capability. */
54
+ auth: "none" | "bearer" | "did";
55
+ /** Optional payment requirement. */
56
+ price?: {
57
+ amount: number;
58
+ currency: string;
59
+ };
60
+ }
61
+
62
+ /** Optional metadata that guides how a renderer produces a human view. */
63
+ export interface RenderHints {
64
+ /** Title shown at the top of the rendered view. */
65
+ title?: string;
66
+ /** Ordered list of fact IDs to feature prominently. */
67
+ primary?: string[];
68
+ /** Ordered list of capability IDs to surface as primary actions. */
69
+ callsToAction?: string[];
70
+ /** Optional theming. */
71
+ theme?: {
72
+ accent?: string;
73
+ };
74
+ }
75
+
76
+ /** A complete Daena document — the atomic unit of publication. */
77
+ export interface DaenaDocument {
78
+ /** Protocol version. */
79
+ daena: "0";
80
+ /** Publisher identity as a Decentralized Identifier. */
81
+ publisher: string;
82
+ /** Signed statements made by the publisher. */
83
+ facts: Fact[];
84
+ /** Actions the publisher offers to agents. */
85
+ capabilities: Capability[];
86
+ /** Optional rendering metadata. */
87
+ render?: RenderHints;
88
+ /** Document-level signature. */
89
+ signature: Signature;
90
+ }