@fide.work/fcp 0.0.1-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.
Files changed (78) hide show
  1. package/README.md +18 -0
  2. package/dist/attestation/create.d.ts +173 -0
  3. package/dist/attestation/create.js +179 -0
  4. package/dist/attestation/index.d.ts +7 -0
  5. package/dist/attestation/index.js +7 -0
  6. package/dist/attestation/verify.d.ts +56 -0
  7. package/dist/attestation/verify.js +94 -0
  8. package/dist/broadcasting/config.d.ts +27 -0
  9. package/dist/broadcasting/config.js +22 -0
  10. package/dist/broadcasting/index.d.ts +7 -0
  11. package/dist/broadcasting/index.js +7 -0
  12. package/dist/broadcasting/registry.d.ts +111 -0
  13. package/dist/broadcasting/registry.js +99 -0
  14. package/dist/experimental/attestation/create.d.ts +173 -0
  15. package/dist/experimental/attestation/create.js +188 -0
  16. package/dist/experimental/attestation/index.d.ts +7 -0
  17. package/dist/experimental/attestation/index.js +7 -0
  18. package/dist/experimental/attestation/verify.d.ts +56 -0
  19. package/dist/experimental/attestation/verify.js +94 -0
  20. package/dist/experimental/broadcasting/config.d.ts +27 -0
  21. package/dist/experimental/broadcasting/config.js +22 -0
  22. package/dist/experimental/broadcasting/index.d.ts +7 -0
  23. package/dist/experimental/broadcasting/index.js +7 -0
  24. package/dist/experimental/broadcasting/registry.d.ts +111 -0
  25. package/dist/experimental/broadcasting/registry.js +99 -0
  26. package/dist/experimental/index.d.ts +9 -0
  27. package/dist/experimental/index.js +13 -0
  28. package/dist/experimental/merkle/index.d.ts +6 -0
  29. package/dist/experimental/merkle/index.js +6 -0
  30. package/dist/experimental/merkle/tree.d.ts +72 -0
  31. package/dist/experimental/merkle/tree.js +154 -0
  32. package/dist/experimental/signing/ed25519.d.ts +116 -0
  33. package/dist/experimental/signing/ed25519.js +161 -0
  34. package/dist/experimental/signing/eip191.d.ts +50 -0
  35. package/dist/experimental/signing/eip191.js +96 -0
  36. package/dist/experimental/signing/eip712.d.ts +112 -0
  37. package/dist/experimental/signing/eip712.js +187 -0
  38. package/dist/experimental/signing/index.d.ts +8 -0
  39. package/dist/experimental/signing/index.js +11 -0
  40. package/dist/fide-id/calculateFideId.d.ts +21 -0
  41. package/dist/fide-id/calculateFideId.js +53 -0
  42. package/dist/fide-id/calculateStatementFideId.d.ts +21 -0
  43. package/dist/fide-id/calculateStatementFideId.js +38 -0
  44. package/dist/fide-id/constants.d.ts +43 -0
  45. package/dist/fide-id/constants.js +55 -0
  46. package/dist/fide-id/index.d.ts +10 -0
  47. package/dist/fide-id/index.js +12 -0
  48. package/dist/fide-id/types.d.ts +52 -0
  49. package/dist/fide-id/types.js +5 -0
  50. package/dist/fide-id/utils.d.ts +30 -0
  51. package/dist/fide-id/utils.js +65 -0
  52. package/dist/index.d.ts +11 -0
  53. package/dist/index.js +19 -0
  54. package/dist/merkle/index.d.ts +6 -0
  55. package/dist/merkle/index.js +6 -0
  56. package/dist/merkle/tree.d.ts +72 -0
  57. package/dist/merkle/tree.js +154 -0
  58. package/dist/schema/evaluations.d.ts +31 -0
  59. package/dist/schema/evaluations.js +31 -0
  60. package/dist/schema/index.d.ts +6 -0
  61. package/dist/schema/index.js +6 -0
  62. package/dist/schema/predicates.d.ts +110 -0
  63. package/dist/schema/predicates.js +122 -0
  64. package/dist/signing/ed25519.d.ts +116 -0
  65. package/dist/signing/ed25519.js +161 -0
  66. package/dist/signing/eip191.d.ts +50 -0
  67. package/dist/signing/eip191.js +96 -0
  68. package/dist/signing/eip712.d.ts +112 -0
  69. package/dist/signing/eip712.js +187 -0
  70. package/dist/signing/index.d.ts +8 -0
  71. package/dist/signing/index.js +11 -0
  72. package/dist/statement/build.d.ts +99 -0
  73. package/dist/statement/build.js +71 -0
  74. package/dist/statement/index.d.ts +6 -0
  75. package/dist/statement/index.js +6 -0
  76. package/dist/statement/policy.d.ts +33 -0
  77. package/dist/statement/policy.js +183 -0
  78. package/package.json +64 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * FCP SDK Statement Building Utilities
3
+ *
4
+ * Helpers for creating statement objects with proper structure.
5
+ */
6
+ import type { FideId, FideEntityType, FideStatementPredicateEntityType, FideStatementPredicateSourceType } from "../fide-id/types.js";
7
+ /**
8
+ * Input for creating a statement.
9
+ *
10
+ * All triples require rawIdentifier + entityType + sourceType. The SDK always computes
11
+ * Fide IDs internally to avoid trust/validation issues with pre-calculated hashes.
12
+ */
13
+ export interface StatementInput {
14
+ /** Subject - raw identifier with entity type and source type */
15
+ subject: {
16
+ rawIdentifier: string;
17
+ entityType: FideEntityType;
18
+ sourceType: FideEntityType;
19
+ };
20
+ /**
21
+ * Predicate - explicit raw identifier with entity type and source type.
22
+ * `rawIdentifier` must be a canonical full URL (https://...).
23
+ * Entity type must be CreativeWork.
24
+ */
25
+ predicate: {
26
+ rawIdentifier: string;
27
+ entityType: FideStatementPredicateEntityType;
28
+ sourceType: FideStatementPredicateSourceType;
29
+ };
30
+ /** Object - raw identifier with entity type and source type */
31
+ object: {
32
+ rawIdentifier: string;
33
+ entityType: FideEntityType;
34
+ sourceType: FideEntityType;
35
+ };
36
+ /** If true, skip URL normalization for raw identifiers while keeping predicate URL validation. */
37
+ ifSkipNormalizeUrl?: boolean;
38
+ }
39
+ /**
40
+ * Complete statement object with all required fields
41
+ *
42
+ * **Important**: Both Fide IDs and raw identifiers are required because:
43
+ * - Fide IDs are one-way hashes - cannot be reversed to get raw identifiers
44
+ * - Protocol specification requires both fields
45
+ * - Indexers need raw identifiers for lookup tables and human-readable display
46
+ * - Enables mapping back to human-readable identifiers for debugging and display
47
+ */
48
+ export interface Statement {
49
+ /** Subject Fide ID */
50
+ subjectFideId: FideId;
51
+ /** Subject raw identifier (required - cannot be derived from Fide ID) */
52
+ subjectRawIdentifier: string;
53
+ /** Predicate Fide ID */
54
+ predicateFideId: FideId;
55
+ /** Predicate raw identifier (required - cannot be derived from Fide ID) */
56
+ predicateRawIdentifier: string;
57
+ /** Object Fide ID */
58
+ objectFideId: FideId;
59
+ /** Object raw identifier (required - cannot be derived from Fide ID) */
60
+ objectRawIdentifier: string;
61
+ /** Statement Fide ID (calculated) */
62
+ statementFideId?: FideId;
63
+ }
64
+ /**
65
+ * Batch build result with deterministic content root.
66
+ */
67
+ export interface StatementBatchWithRoot {
68
+ statements: Statement[];
69
+ statementFideIds: FideId[];
70
+ /** Deterministic SHA-256 hex hash of ordered statement Fide IDs. */
71
+ root: string;
72
+ }
73
+ /**
74
+ * Create a statement object with all required fields.
75
+ *
76
+ * Always computes Fide IDs from rawIdentifier + entityType + sourceType.
77
+ * Predicates must be canonical full URLs.
78
+ *
79
+ * @param input - Statement input with subject, predicate, and object
80
+ * @paramDefault input { subject: { rawIdentifier: "https://x.com/alice", entityType: "Person", sourceType: "Product" }, predicate: { rawIdentifier: "https://schema.org/name", entityType: "CreativeWork", sourceType: "Product" }, object: { rawIdentifier: "Alice", entityType: "CreativeWork", sourceType: "CreativeWork" } }
81
+ * @returns Complete statement object
82
+ * @throws Error if statement input policy fails, Fide ID format/policy checks fail, or statement ID derivation fails
83
+ */
84
+ export declare function createStatement(input: StatementInput): Promise<Statement>;
85
+ /**
86
+ * Build a batch of statements and derive a deterministic batch root.
87
+ *
88
+ * Root derivation:
89
+ * - `statementFideIds` are lexicographically sorted
90
+ * - Sorted IDs are joined with `\\n`
91
+ * - SHA-256 is computed over that byte sequence
92
+ * - Result is returned as lowercase hex string
93
+ *
94
+ * @param inputs Array of statement inputs.
95
+ * @paramDefault inputs [{ subject: { rawIdentifier: "https://x.com/alice", entityType: "Person", sourceType: "Product" }, predicate: { rawIdentifier: "https://schema.org/name", entityType: "CreativeWork", sourceType: "Product" }, object: { rawIdentifier: "Alice", entityType: "CreativeWork", sourceType: "CreativeWork" } }, { subject: { rawIdentifier: "https://x.com/bob", entityType: "Person", sourceType: "Product" }, predicate: { rawIdentifier: "https://schema.org/worksFor", entityType: "CreativeWork", sourceType: "Product" }, object: { rawIdentifier: "https://www.acme.com", entityType: "Organization", sourceType: "Product" } }]
96
+ * @returns Statements, statement IDs (input order), and deterministic root hash
97
+ * @throws Error if one or more built statements are missing `statementFideId`
98
+ */
99
+ export declare function batchStatementsWithRoot(inputs: StatementInput[]): Promise<StatementBatchWithRoot>;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * FCP SDK Statement Building Utilities
3
+ *
4
+ * Helpers for creating statement objects with proper structure.
5
+ */
6
+ import { calculateFideId, calculateStatementFideId } from "../fide-id/index.js";
7
+ import { assertStatementFideIdsPolicy, assertStatementInputPolicy, normalizeIfUrlLike, normalizePredicateRawIdentifier } from "./policy.js";
8
+ import { createHash } from "node:crypto";
9
+ /**
10
+ * Create a statement object with all required fields.
11
+ *
12
+ * Always computes Fide IDs from rawIdentifier + entityType + sourceType.
13
+ * Predicates must be canonical full URLs.
14
+ *
15
+ * @param input - Statement input with subject, predicate, and object
16
+ * @paramDefault input { subject: { rawIdentifier: "https://x.com/alice", entityType: "Person", sourceType: "Product" }, predicate: { rawIdentifier: "https://schema.org/name", entityType: "CreativeWork", sourceType: "Product" }, object: { rawIdentifier: "Alice", entityType: "CreativeWork", sourceType: "CreativeWork" } }
17
+ * @returns Complete statement object
18
+ * @throws Error if statement input policy fails, Fide ID format/policy checks fail, or statement ID derivation fails
19
+ */
20
+ export async function createStatement(input) {
21
+ assertStatementInputPolicy(input);
22
+ const ifSkipNormalizeUrl = input.ifSkipNormalizeUrl === true;
23
+ const subjectRawIdentifier = normalizeIfUrlLike(input.subject.rawIdentifier, ifSkipNormalizeUrl);
24
+ const predicateRawIdentifier = normalizePredicateRawIdentifier(input.predicate.rawIdentifier, ifSkipNormalizeUrl);
25
+ const objectRawIdentifier = normalizeIfUrlLike(input.object.rawIdentifier, ifSkipNormalizeUrl);
26
+ const subjectFideId = await calculateFideId(input.subject.entityType, input.subject.sourceType, subjectRawIdentifier);
27
+ const predicateFideId = await calculateFideId(input.predicate.entityType, input.predicate.sourceType, predicateRawIdentifier);
28
+ const objectFideId = await calculateFideId(input.object.entityType, input.object.sourceType, objectRawIdentifier);
29
+ assertStatementFideIdsPolicy(subjectFideId, predicateFideId, objectFideId);
30
+ // Calculate statement Fide ID
31
+ const statementFideId = await calculateStatementFideId(subjectFideId, predicateFideId, objectFideId);
32
+ return {
33
+ subjectFideId,
34
+ subjectRawIdentifier,
35
+ predicateFideId,
36
+ predicateRawIdentifier,
37
+ objectFideId,
38
+ objectRawIdentifier,
39
+ statementFideId
40
+ };
41
+ }
42
+ /**
43
+ * Build a batch of statements and derive a deterministic batch root.
44
+ *
45
+ * Root derivation:
46
+ * - `statementFideIds` are lexicographically sorted
47
+ * - Sorted IDs are joined with `\\n`
48
+ * - SHA-256 is computed over that byte sequence
49
+ * - Result is returned as lowercase hex string
50
+ *
51
+ * @param inputs Array of statement inputs.
52
+ * @paramDefault inputs [{ subject: { rawIdentifier: "https://x.com/alice", entityType: "Person", sourceType: "Product" }, predicate: { rawIdentifier: "https://schema.org/name", entityType: "CreativeWork", sourceType: "Product" }, object: { rawIdentifier: "Alice", entityType: "CreativeWork", sourceType: "CreativeWork" } }, { subject: { rawIdentifier: "https://x.com/bob", entityType: "Person", sourceType: "Product" }, predicate: { rawIdentifier: "https://schema.org/worksFor", entityType: "CreativeWork", sourceType: "Product" }, object: { rawIdentifier: "https://www.acme.com", entityType: "Organization", sourceType: "Product" } }]
53
+ * @returns Statements, statement IDs (input order), and deterministic root hash
54
+ * @throws Error if one or more built statements are missing `statementFideId`
55
+ */
56
+ export async function batchStatementsWithRoot(inputs) {
57
+ const statements = await Promise.all(inputs.map((input) => createStatement(input)));
58
+ const statementFideIds = statements
59
+ .map((s) => s.statementFideId)
60
+ .filter((id) => !!id);
61
+ if (statementFideIds.length !== statements.length) {
62
+ throw new Error("Batch build failed: one or more statements are missing statementFideId.");
63
+ }
64
+ const canonicalIds = [...statementFideIds].sort();
65
+ const root = createHash("sha256").update(canonicalIds.join("\n")).digest("hex");
66
+ return {
67
+ statements,
68
+ statementFideIds,
69
+ root
70
+ };
71
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * FCP SDK - Statement Module
3
+ *
4
+ * Re-exports all statement utilities.
5
+ */
6
+ export { createStatement, batchStatementsWithRoot, type StatementInput, type Statement, type StatementBatchWithRoot } from "./build.js";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * FCP SDK - Statement Module
3
+ *
4
+ * Re-exports all statement utilities.
5
+ */
6
+ export { createStatement, batchStatementsWithRoot } from "./build.js";
@@ -0,0 +1,33 @@
1
+ import type { StatementInput } from "./build.js";
2
+ /**
3
+ * Enforce statement input policy before deriving Fide IDs.
4
+ */
5
+ export declare function assertStatementInputPolicy(input: StatementInput): void;
6
+ /**
7
+ * Normalize rawIdentifier only when it is URL-like (http/https).
8
+ *
9
+ * Rules for URL-like values:
10
+ * - must parse as an absolute URL
11
+ * - lowercase scheme + host
12
+ * - remove default ports (80 for http, 443 for https)
13
+ * - preserve path/query/fragment case
14
+ *
15
+ * Non URL-like values are returned unchanged.
16
+ */
17
+ export declare function normalizeIfUrlLike(rawIdentifier: string, ifSkipNormalizeUrl?: boolean): string;
18
+ /**
19
+ * Canonicalize and validate predicate rawIdentifier URLs.
20
+ *
21
+ * Policy:
22
+ * - must be an absolute URL
23
+ * - must use https
24
+ * - username/password are not allowed
25
+ * - normalize scheme + host case only
26
+ * - remove default https port (443)
27
+ * - preserve path/query/fragment case
28
+ */
29
+ export declare function normalizePredicateRawIdentifier(rawIdentifier: string, ifSkipNormalizeUrl?: boolean): string;
30
+ /**
31
+ * Enforce statement ID policy after deriving subject/predicate/object Fide IDs.
32
+ */
33
+ export declare function assertStatementFideIdsPolicy(subjectFideId: string, predicateFideId: string, objectFideId: string): void;
@@ -0,0 +1,183 @@
1
+ import { assertFideId, parseFideId } from "../fide-id/index.js";
2
+ function describeValue(value) {
3
+ if (value === null)
4
+ return "null";
5
+ if (value === undefined)
6
+ return "undefined";
7
+ const kind = typeof value;
8
+ if (kind === "string")
9
+ return `string(${JSON.stringify(value)})`;
10
+ if (kind === "number" || kind === "boolean" || kind === "bigint")
11
+ return `${kind}(${String(value)})`;
12
+ if (kind === "function")
13
+ return "function";
14
+ if (Array.isArray(value))
15
+ return `array(len=${value.length})`;
16
+ if (kind === "object") {
17
+ try {
18
+ return `object(${JSON.stringify(value)})`;
19
+ }
20
+ catch {
21
+ return "object([unserializable])";
22
+ }
23
+ }
24
+ return kind;
25
+ }
26
+ /**
27
+ * Enforce statement input policy before deriving Fide IDs.
28
+ */
29
+ export function assertStatementInputPolicy(input) {
30
+ if (!input || typeof input !== "object") {
31
+ throw new Error(`Invalid statement input: expected object with subject, predicate, and object; got ${describeValue(input)}.`);
32
+ }
33
+ if (!input.subject || typeof input.subject !== "object") {
34
+ throw new Error(`Invalid statement input: expected subject object; got ${describeValue(input.subject)}.`);
35
+ }
36
+ if (!input.predicate || typeof input.predicate !== "object") {
37
+ throw new Error(`Invalid statement input: expected predicate object; got ${describeValue(input.predicate)}.`);
38
+ }
39
+ if (!input.object || typeof input.object !== "object") {
40
+ throw new Error(`Invalid statement input: expected object object at input.object; got ${describeValue(input.object)}.`);
41
+ }
42
+ if (typeof input.subject.rawIdentifier !== "string") {
43
+ throw new Error(`Invalid statement input: expected subject.rawIdentifier as string; got ${describeValue(input.subject?.rawIdentifier)}.`);
44
+ }
45
+ if (typeof input.subject.entityType !== "string") {
46
+ throw new Error(`Invalid statement input: expected subject.entityType as string; got ${describeValue(input.subject?.entityType)}.`);
47
+ }
48
+ if (typeof input.subject.sourceType !== "string") {
49
+ throw new Error(`Invalid statement input: expected subject.sourceType as string; got ${describeValue(input.subject?.sourceType)}.`);
50
+ }
51
+ if (typeof input.predicate.rawIdentifier !== "string") {
52
+ throw new Error(`Invalid statement input: expected predicate.rawIdentifier as string; got ${describeValue(input.predicate?.rawIdentifier)}.`);
53
+ }
54
+ if (typeof input.predicate.entityType !== "string") {
55
+ throw new Error(`Invalid statement input: expected predicate.entityType as string; got ${describeValue(input.predicate?.entityType)}.`);
56
+ }
57
+ if (typeof input.predicate.sourceType !== "string") {
58
+ throw new Error(`Invalid statement input: expected predicate.sourceType as string; got ${describeValue(input.predicate?.sourceType)}.`);
59
+ }
60
+ if (typeof input.object.rawIdentifier !== "string") {
61
+ throw new Error(`Invalid statement input: expected object.rawIdentifier as string; got ${describeValue(input.object?.rawIdentifier)}.`);
62
+ }
63
+ if (typeof input.object.entityType !== "string") {
64
+ throw new Error(`Invalid statement input: expected object.entityType as string; got ${describeValue(input.object?.entityType)}.`);
65
+ }
66
+ if (typeof input.object.sourceType !== "string") {
67
+ throw new Error(`Invalid statement input: expected object.sourceType as string; got ${describeValue(input.object?.sourceType)}.`);
68
+ }
69
+ if (input.predicate.entityType !== "CreativeWork") {
70
+ throw new Error(`Invalid predicate entityType: ${input.predicate.entityType}. Expected CreativeWork.`);
71
+ }
72
+ if (input.predicate.sourceType !== "Product") {
73
+ throw new Error(`Invalid predicate sourceType: ${input.predicate.sourceType}. Expected Product.`);
74
+ }
75
+ // Predicate URL validity/canonicalization is enforced by normalizePredicateRawIdentifier()
76
+ // in the statement building path.
77
+ }
78
+ /**
79
+ * Normalize rawIdentifier only when it is URL-like (http/https).
80
+ *
81
+ * Rules for URL-like values:
82
+ * - must parse as an absolute URL
83
+ * - lowercase scheme + host
84
+ * - remove default ports (80 for http, 443 for https)
85
+ * - preserve path/query/fragment case
86
+ *
87
+ * Non URL-like values are returned unchanged.
88
+ */
89
+ export function normalizeIfUrlLike(rawIdentifier, ifSkipNormalizeUrl = false) {
90
+ if (ifSkipNormalizeUrl) {
91
+ return rawIdentifier;
92
+ }
93
+ if (!/^https?:\/\//i.test(rawIdentifier)) {
94
+ return rawIdentifier;
95
+ }
96
+ let url;
97
+ try {
98
+ url = new URL(rawIdentifier);
99
+ }
100
+ catch {
101
+ throw new Error(`Invalid URL-like rawIdentifier: ${rawIdentifier}. Expected absolute URL when using http(s) format.`);
102
+ }
103
+ const protocol = url.protocol.toLowerCase();
104
+ if (protocol !== "http:" && protocol !== "https:") {
105
+ return rawIdentifier;
106
+ }
107
+ url.protocol = protocol;
108
+ url.hostname = url.hostname.toLowerCase();
109
+ if ((protocol === "https:" && url.port === "443") || (protocol === "http:" && url.port === "80")) {
110
+ url.port = "";
111
+ }
112
+ return url.toString();
113
+ }
114
+ /**
115
+ * Canonicalize and validate predicate rawIdentifier URLs.
116
+ *
117
+ * Policy:
118
+ * - must be an absolute URL
119
+ * - must use https
120
+ * - username/password are not allowed
121
+ * - normalize scheme + host case only
122
+ * - remove default https port (443)
123
+ * - preserve path/query/fragment case
124
+ */
125
+ export function normalizePredicateRawIdentifier(rawIdentifier, ifSkipNormalizeUrl = false) {
126
+ if (ifSkipNormalizeUrl) {
127
+ let skipUrl;
128
+ try {
129
+ skipUrl = new URL(rawIdentifier);
130
+ }
131
+ catch {
132
+ throw new Error(`Invalid predicate rawIdentifier: ${rawIdentifier}. Expected canonical full URL (e.g. https://schema.org/name).`);
133
+ }
134
+ if (skipUrl.protocol.toLowerCase() !== "https:") {
135
+ throw new Error(`Invalid predicate rawIdentifier protocol: ${rawIdentifier}. Expected https URL.`);
136
+ }
137
+ if (skipUrl.username || skipUrl.password) {
138
+ throw new Error(`Invalid predicate rawIdentifier: ${rawIdentifier}. URL userinfo is not allowed.`);
139
+ }
140
+ return rawIdentifier;
141
+ }
142
+ const normalized = normalizeIfUrlLike(rawIdentifier, ifSkipNormalizeUrl);
143
+ let url;
144
+ try {
145
+ url = new URL(normalized);
146
+ }
147
+ catch {
148
+ throw new Error(`Invalid predicate rawIdentifier: ${rawIdentifier}. Expected canonical full URL (e.g. https://schema.org/name).`);
149
+ }
150
+ if (url.protocol.toLowerCase() !== "https:") {
151
+ throw new Error(`Invalid predicate rawIdentifier protocol: ${rawIdentifier}. Expected https URL.`);
152
+ }
153
+ if (url.username || url.password) {
154
+ throw new Error(`Invalid predicate rawIdentifier: ${rawIdentifier}. URL userinfo is not allowed.`);
155
+ }
156
+ url.protocol = "https:";
157
+ url.hostname = url.hostname.toLowerCase();
158
+ if (url.port === "443") {
159
+ url.port = "";
160
+ }
161
+ return url.toString();
162
+ }
163
+ /**
164
+ * Enforce statement ID policy after deriving subject/predicate/object Fide IDs.
165
+ */
166
+ export function assertStatementFideIdsPolicy(subjectFideId, predicateFideId, objectFideId) {
167
+ // Predicate combo policy is enforced at input level (entityType/sourceType).
168
+ // Keep ID-level checks here for subject/object Statement-source restrictions.
169
+ assertRoleFideIdPolicy(subjectFideId, "subject");
170
+ assertRoleFideIdPolicy(objectFideId, "object");
171
+ }
172
+ function assertRoleFideIdPolicy(fideId, role) {
173
+ assertFideId(fideId);
174
+ const { typeChar, sourceChar } = parseFideId(fideId);
175
+ if (sourceChar !== "0")
176
+ return;
177
+ if (typeChar === "0")
178
+ return;
179
+ const label = role ? ` ${role}` : "";
180
+ throw new Error(`Invalid Fide ID for statement${label}: ${fideId}. ` +
181
+ `Protocol disallows Statement source (0xX0) for non-Statement entities. ` +
182
+ `Use a concrete source (e.g. Product 0x15, Organization 0x25) instead of Statement-derived IDs.`);
183
+ }
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@fide.work/fcp",
3
+ "version": "0.0.1-alpha.0",
4
+ "description": "Fide Context Protocol SDK (v0)",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/fide-work/fcp.git"
9
+ },
10
+ "homepage": "https://fide.work/fcp",
11
+ "keywords": [
12
+ "fide",
13
+ "fcp",
14
+ "did",
15
+ "identity",
16
+ "contest",
17
+ "memory"
18
+ ],
19
+ "sideEffects": false,
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "peerDependencies": {
40
+ "viem": "^2.0.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "viem": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "devDependencies": {
48
+ "@types/node": "^22.13.10",
49
+ "typescript": "^5.9.3",
50
+ "viem": "^2.21.48"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc -p tsconfig.json",
54
+ "check-types": "tsc --noEmit",
55
+ "test": "pnpm run build && node scripts/test-runner.mjs",
56
+ "test:verbose": "pnpm run build && node scripts/test-runner.mjs --verbose",
57
+ "experimental:guard": "node -e \"if (process.env.FCP_EXPERIMENTAL !== '1') { console.error('Experimental examples are disabled. Re-run with FCP_EXPERIMENTAL=1'); process.exit(1); }\"",
58
+ "example": "pnpm run build && node examples/fide-id/basic-usage.mjs",
59
+ "example:fide-id": "pnpm run build && node examples/fide-id/basic-usage.mjs",
60
+ "example:statement": "pnpm run build && node examples/statement/statement-example.mjs",
61
+ "example:experimental": "pnpm run experimental:guard && pnpm run build && node scripts/run-experimental-example.mjs",
62
+ "example:schema": "pnpm run build && node examples/schema/schema-example.mjs"
63
+ }
64
+ }