@native-knowledge/knowledge-sdk 0.0.0-stage → 0.1.0-rc.2

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 (203) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +29 -0
  3. package/README.md +34 -2
  4. package/dist/agent-entry.d.ts +291 -0
  5. package/dist/agent-entry.js +153 -0
  6. package/dist/agent-guidance-error.d.ts +15 -0
  7. package/dist/agent-guidance-error.js +46 -0
  8. package/dist/auth.d.ts +124 -0
  9. package/dist/auth.js +165 -0
  10. package/dist/index.d.ts +290 -0
  11. package/dist/index.js +166 -0
  12. package/dist/internal/contracts/artifact.d.ts +120 -0
  13. package/dist/internal/contracts/artifact.js +103 -0
  14. package/dist/internal/contracts/collection-control.d.ts +160 -0
  15. package/dist/internal/contracts/collection-control.js +69 -0
  16. package/dist/internal/contracts/collection.d.ts +263 -0
  17. package/dist/internal/contracts/collection.js +174 -0
  18. package/dist/internal/contracts/common.d.ts +17 -0
  19. package/dist/internal/contracts/common.js +16 -0
  20. package/dist/internal/contracts/currentness.d.ts +477 -0
  21. package/dist/internal/contracts/currentness.js +221 -0
  22. package/dist/internal/contracts/event.d.ts +60 -0
  23. package/dist/internal/contracts/event.js +35 -0
  24. package/dist/internal/contracts/evidence.d.ts +202 -0
  25. package/dist/internal/contracts/evidence.js +171 -0
  26. package/dist/internal/contracts/index.d.ts +54 -0
  27. package/dist/internal/contracts/index.js +54 -0
  28. package/dist/internal/contracts/material-capability.d.ts +88 -0
  29. package/dist/internal/contracts/material-capability.js +8 -0
  30. package/dist/internal/contracts/material-carrier.d.ts +104 -0
  31. package/dist/internal/contracts/material-carrier.js +15 -0
  32. package/dist/internal/contracts/material-context.d.ts +28 -0
  33. package/dist/internal/contracts/material-context.js +9 -0
  34. package/dist/internal/contracts/material-read.d.ts +152 -0
  35. package/dist/internal/contracts/material-read.js +12 -0
  36. package/dist/internal/contracts/observation.d.ts +75 -0
  37. package/dist/internal/contracts/observation.js +39 -0
  38. package/dist/internal/contracts/persistence.d.ts +370 -0
  39. package/dist/internal/contracts/persistence.js +239 -0
  40. package/dist/internal/contracts/project-intent.d.ts +218 -0
  41. package/dist/internal/contracts/project-intent.js +121 -0
  42. package/dist/internal/contracts/projection.d.ts +380 -0
  43. package/dist/internal/contracts/projection.js +194 -0
  44. package/dist/internal/contracts/public-reference.d.ts +237 -0
  45. package/dist/internal/contracts/public-reference.js +87 -0
  46. package/dist/internal/contracts/reference-record.d.ts +124 -0
  47. package/dist/internal/contracts/reference-record.js +55 -0
  48. package/dist/internal/contracts/remote-file.d.ts +128 -0
  49. package/dist/internal/contracts/remote-file.js +159 -0
  50. package/dist/internal/contracts/resource-scope.d.ts +40 -0
  51. package/dist/internal/contracts/resource-scope.js +38 -0
  52. package/dist/internal/contracts/review-packet.d.ts +274 -0
  53. package/dist/internal/contracts/review-packet.js +61 -0
  54. package/dist/internal/contracts/review-plane.d.ts +90 -0
  55. package/dist/internal/contracts/review-plane.js +89 -0
  56. package/dist/internal/contracts/rich-document.d.ts +641 -0
  57. package/dist/internal/contracts/rich-document.js +184 -0
  58. package/dist/internal/contracts/runtime-compatibility.d.ts +22 -0
  59. package/dist/internal/contracts/runtime-compatibility.js +55 -0
  60. package/dist/internal/contracts/runtime.d.ts +59 -0
  61. package/dist/internal/contracts/runtime.js +68 -0
  62. package/dist/internal/contracts/scheduler.d.ts +348 -0
  63. package/dist/internal/contracts/scheduler.js +256 -0
  64. package/dist/internal/contracts/signal.d.ts +113 -0
  65. package/dist/internal/contracts/signal.js +77 -0
  66. package/dist/internal/contracts/source-governance.d.ts +375 -0
  67. package/dist/internal/contracts/source-governance.js +194 -0
  68. package/dist/internal/contracts/source.d.ts +62 -0
  69. package/dist/internal/contracts/source.js +32 -0
  70. package/dist/internal/contracts/tenant-budget.d.ts +59 -0
  71. package/dist/internal/contracts/tenant-budget.js +34 -0
  72. package/dist/internal/contracts/tenant-collection-request.d.ts +209 -0
  73. package/dist/internal/contracts/tenant-collection-request.js +58 -0
  74. package/dist/internal/contracts/tenant-collection.d.ts +199 -0
  75. package/dist/internal/contracts/tenant-collection.js +66 -0
  76. package/dist/internal/contracts/tenant-currentness.d.ts +117 -0
  77. package/dist/internal/contracts/tenant-currentness.js +26 -0
  78. package/dist/internal/contracts/tenant-management.d.ts +286 -0
  79. package/dist/internal/contracts/tenant-management.js +27 -0
  80. package/dist/internal/contracts/tenant-material-api.d.ts +584 -0
  81. package/dist/internal/contracts/tenant-material-api.js +46 -0
  82. package/dist/internal/contracts/tenant-material-json-schema.js +16 -0
  83. package/dist/internal/contracts/tenant-pdf-text.d.ts +27 -0
  84. package/dist/internal/contracts/tenant-pdf-text.js +13 -0
  85. package/dist/internal/contracts/tenant-project-control.d.ts +94 -0
  86. package/dist/internal/contracts/tenant-project-control.js +19 -0
  87. package/dist/internal/contracts/tenant-public-reference.d.ts +179 -0
  88. package/dist/internal/contracts/tenant-public-reference.js +26 -0
  89. package/dist/internal/contracts/tenant-resource-api.d.ts +738 -0
  90. package/dist/internal/contracts/tenant-resource-api.js +70 -0
  91. package/dist/internal/contracts/tenant-resource.d.ts +298 -0
  92. package/dist/internal/contracts/tenant-resource.js +118 -0
  93. package/dist/internal/contracts/tenant-rich-document.d.ts +317 -0
  94. package/dist/internal/contracts/tenant-rich-document.js +17 -0
  95. package/dist/internal/contracts/tenant-source-binding.d.ts +44 -0
  96. package/dist/internal/contracts/tenant-source-binding.js +33 -0
  97. package/dist/internal/contracts/tenant-source-bridge.d.ts +70 -0
  98. package/dist/internal/contracts/tenant-source-bridge.js +9 -0
  99. package/dist/internal/contracts/tenant-source-cutover.d.ts +226 -0
  100. package/dist/internal/contracts/tenant-source-cutover.js +26 -0
  101. package/dist/internal/contracts/tenant-source-document.d.ts +163 -0
  102. package/dist/internal/contracts/tenant-source-document.js +38 -0
  103. package/dist/internal/contracts/tenant-source-lease.d.ts +1 -0
  104. package/dist/internal/contracts/tenant-source-lease.js +5 -0
  105. package/dist/internal/contracts/tenant-source.d.ts +223 -0
  106. package/dist/internal/contracts/tenant-source.js +83 -0
  107. package/dist/internal/contracts/tenant-web-collection.d.ts +287 -0
  108. package/dist/internal/contracts/tenant-web-collection.js +118 -0
  109. package/dist/internal/contracts/tenant-web-content-plan.d.ts +86 -0
  110. package/dist/internal/contracts/tenant-web-content-plan.js +39 -0
  111. package/dist/internal/contracts/tenant-web-content-result.d.ts +63 -0
  112. package/dist/internal/contracts/tenant-web-content-result.js +15 -0
  113. package/dist/internal/contracts/tenant-web-content.d.ts +383 -0
  114. package/dist/internal/contracts/tenant-web-content.js +16 -0
  115. package/dist/internal/contracts/tenant-web-crawl.d.ts +310 -0
  116. package/dist/internal/contracts/tenant-web-crawl.js +55 -0
  117. package/dist/internal/contracts/tenant-web-dynamic.d.ts +698 -0
  118. package/dist/internal/contracts/tenant-web-dynamic.js +68 -0
  119. package/dist/internal/contracts/tenant-web-results.d.ts +66 -0
  120. package/dist/internal/contracts/tenant-web-results.js +41 -0
  121. package/dist/internal/contracts/tenant-web-workflow.d.ts +494 -0
  122. package/dist/internal/contracts/tenant-web-workflow.js +29 -0
  123. package/dist/internal/serving-contracts/agent-catalog.d.ts +70 -0
  124. package/dist/internal/serving-contracts/agent-catalog.js +56 -0
  125. package/dist/internal/serving-contracts/agent-entry.d.ts +13148 -0
  126. package/dist/internal/serving-contracts/agent-entry.js +57 -0
  127. package/dist/internal/serving-contracts/agent-guidance-shapes.d.ts +263 -0
  128. package/dist/internal/serving-contracts/agent-guidance-shapes.js +12 -0
  129. package/dist/internal/serving-contracts/agent-input-hints.d.ts +24 -0
  130. package/dist/internal/serving-contracts/agent-input-hints.js +104 -0
  131. package/dist/internal/serving-contracts/body-search.d.ts +231 -0
  132. package/dist/internal/serving-contracts/body-search.js +16 -0
  133. package/dist/internal/serving-contracts/consumer.d.ts +989 -0
  134. package/dist/internal/serving-contracts/consumer.js +45 -0
  135. package/dist/internal/serving-contracts/core.d.ts +333 -0
  136. package/dist/internal/serving-contracts/core.js +76 -0
  137. package/dist/internal/serving-contracts/http.d.ts +2874 -0
  138. package/dist/internal/serving-contracts/http.js +64 -0
  139. package/dist/internal/serving-contracts/index.d.ts +24 -0
  140. package/dist/internal/serving-contracts/index.js +25 -0
  141. package/dist/internal/serving-contracts/management.d.ts +424 -0
  142. package/dist/internal/serving-contracts/management.js +15 -0
  143. package/dist/internal/serving-contracts/material-capabilities.d.ts +508 -0
  144. package/dist/internal/serving-contracts/material-capabilities.js +14 -0
  145. package/dist/internal/serving-contracts/material-index-status.d.ts +55 -0
  146. package/dist/internal/serving-contracts/material-index-status.js +5 -0
  147. package/dist/internal/serving-contracts/mcp.d.ts +2218 -0
  148. package/dist/internal/serving-contracts/mcp.js +140 -0
  149. package/dist/internal/serving-contracts/tenant-governance.d.ts +236 -0
  150. package/dist/internal/serving-contracts/tenant-governance.js +13 -0
  151. package/dist/internal/serving-contracts/tenant-management.d.ts +6276 -0
  152. package/dist/internal/serving-contracts/tenant-management.js +89 -0
  153. package/dist/internal/serving-contracts/tenant-project.d.ts +7550 -0
  154. package/dist/internal/serving-contracts/tenant-project.js +39 -0
  155. package/dist/internal/serving-contracts/tenant-runtime.d.ts +9674 -0
  156. package/dist/internal/serving-contracts/tenant-runtime.js +37 -0
  157. package/dist/internal/serving-contracts/tenant-session.d.ts +87 -0
  158. package/dist/internal/serving-contracts/tenant-session.js +8 -0
  159. package/dist/internal/serving-contracts/tenant-web-content.d.ts +4606 -0
  160. package/dist/internal/serving-contracts/tenant-web-content.js +20 -0
  161. package/dist/internal/serving-contracts/tenant-web-crawl.d.ts +2958 -0
  162. package/dist/internal/serving-contracts/tenant-web-crawl.js +13 -0
  163. package/dist/internal/serving-contracts/tenant-web-dynamic.d.ts +3902 -0
  164. package/dist/internal/serving-contracts/tenant-web-dynamic.js +20 -0
  165. package/dist/internal/serving-contracts/tenant-web-workflow.d.ts +5750 -0
  166. package/dist/internal/serving-contracts/tenant-web-workflow.js +36 -0
  167. package/dist/internal/serving-contracts/tenant-web.d.ts +6418 -0
  168. package/dist/internal/serving-contracts/tenant-web.js +53 -0
  169. package/dist/internal/serving-contracts/tenant-workspace.d.ts +6451 -0
  170. package/dist/internal/serving-contracts/tenant-workspace.js +28 -0
  171. package/dist/internal/serving-contracts/workflow.d.ts +439 -0
  172. package/dist/internal/serving-contracts/workflow.js +37 -0
  173. package/dist/material-stream.d.ts +18 -0
  174. package/dist/material-stream.js +29 -0
  175. package/dist/oauth.d.ts +268 -0
  176. package/dist/oauth.js +539 -0
  177. package/dist/resource.d.ts +88 -0
  178. package/dist/resource.js +123 -0
  179. package/dist/session.d.ts +4 -0
  180. package/dist/session.js +3 -0
  181. package/dist/tenant-client.d.ts +169 -0
  182. package/dist/tenant-client.js +58 -0
  183. package/dist/tenant-management.d.ts +240 -0
  184. package/dist/tenant-management.js +149 -0
  185. package/dist/tenant-project.d.ts +57 -0
  186. package/dist/tenant-project.js +63 -0
  187. package/dist/tenant-runtime.d.ts +174 -0
  188. package/dist/tenant-runtime.js +17 -0
  189. package/dist/tenant-web-content.d.ts +44 -0
  190. package/dist/tenant-web-content.js +70 -0
  191. package/dist/tenant-web-crawl.d.ts +42 -0
  192. package/dist/tenant-web-crawl.js +39 -0
  193. package/dist/tenant-web-dynamic.d.ts +42 -0
  194. package/dist/tenant-web-dynamic.js +39 -0
  195. package/dist/tenant-web-workflow.d.ts +43 -0
  196. package/dist/tenant-web-workflow.js +63 -0
  197. package/dist/tenant-web.d.ts +42 -0
  198. package/dist/tenant-web.js +39 -0
  199. package/dist/tenant-workspace.d.ts +36 -0
  200. package/dist/tenant-workspace.js +21 -0
  201. package/dist/token-provider.d.ts +14 -0
  202. package/dist/token-provider.js +21 -0
  203. package/package.json +45 -3
@@ -0,0 +1,70 @@
1
+ /** Provider 16 的格式 2 资源读取合同;旧 Project/Tenant wire 保持其严格 schema。 */
2
+ import { z } from 'zod';
3
+ import { stableUriSchema, projectKeySchema, sha256Schema, accessClassificationSchema } from './common.js';
4
+ import { materialContextSchema } from './material-context.js';
5
+ import { materialAuthorityPolicySchema, resourceScopeSchema, parseTenantResourceRef, tenantStorageKey } from './resource-scope.js';
6
+ import { tenantResourceOriginSchema } from './tenant-resource.js';
7
+ import { rawRetrievalDecisionSchema, rawContentDescriptorSchema } from './material-read.js';
8
+ import { materialResourceTypeSchema } from './material-carrier.js';
9
+ import { tenantMaterialProviderSchema, tenantMaterialDataSchemas } from './tenant-material-api.js';
10
+ export const resourceOriginSchema = z.union([tenantResourceOriginSchema, z.object({ type: z.literal('LEGACY_PROJECT'), projectKey: projectKeySchema, projectRef: stableUriSchema }).strict()]);
11
+ export const resourceDirectoryItemSchema = z.object({
12
+ ref: stableUriSchema, ownerTenantId: resourceScopeSchema.options[0].shape.tenantId, resourceType: materialResourceTypeSchema,
13
+ origin: resourceOriginSchema, identityHash: sha256Schema, identityKind: z.enum(['CAS_BYTES', 'REFERENCE_RECORD_DIGEST']),
14
+ kind: z.string().min(1).max(128), classification: accessClassificationSchema, mediaType: z.string().min(1).max(256),
15
+ title: z.string().max(512), summary: z.string().max(1024), decision: rawRetrievalDecisionSchema,
16
+ }).strict().superRefine((value, ctx) => {
17
+ if (value.origin.type === 'LEGACY_PROJECT') {
18
+ if (value.origin.projectRef !== `knowledge-project://${value.origin.projectKey}/tenant/${encodeURIComponent(value.ownerTenantId)}` || value.identityKind !== (value.resourceType === 'reference' ? 'REFERENCE_RECORD_DIGEST' : 'CAS_BYTES'))
19
+ ctx.addIssue({ code: 'custom', path: ['origin'], message: 'Legacy origin/identity mismatch' });
20
+ }
21
+ else {
22
+ const ref = parseTenantResourceRef(value.ref), key = tenantStorageKey(value.ownerTenantId);
23
+ if (!ref || ref.storageKey !== key || ref.resourceType !== value.resourceType || value.identityKind !== 'CAS_BYTES')
24
+ ctx.addIssue({ code: 'custom', path: ['ref'], message: 'Native owner/resource identity mismatch' });
25
+ if (value.origin.type === 'TENANT_AUTHOR' && value.origin.actor.tenantId !== value.ownerTenantId)
26
+ ctx.addIssue({ code: 'custom', path: ['origin'], message: 'Author Tenant mismatch' });
27
+ if (value.origin.type === 'TENANT_SOURCE') {
28
+ const prefix = `tenant-source://${key}/${encodeURIComponent(value.origin.sourceId)}`;
29
+ if (value.origin.sourceRef !== prefix || !value.origin.sourceRevisionRef.startsWith(prefix + '/v/') || !/^[a-f0-9]{64}$/.test(value.origin.sourceRevisionRef.slice(prefix.length + 3)))
30
+ ctx.addIssue({ code: 'custom', path: ['origin'], message: 'Source Tenant/revision mismatch' });
31
+ }
32
+ }
33
+ });
34
+ const context = { projectRef: stableUriSchema.optional() }, position = z.string().min(1).max(4096).optional(), limit = z.number().int().min(1).max(100).optional();
35
+ const filters = { resourceType: materialResourceTypeSchema.optional(), sourceProjectKey: projectKeySchema.optional(), refPrefix: z.string().max(256).regex(/^[a-z][a-z0-9+.-]*:\/\/[!-~]*$/i).optional() };
36
+ const ref = z.object({ ...context, ref: stableUriSchema }).strict();
37
+ export const resourceToolSchemas = {
38
+ knowledge_resource_list: z.object({ ...context, after: position, limit, ...filters }).strict(),
39
+ knowledge_resource_describe: ref, knowledge_resource_read: ref, knowledge_resource_capabilities: ref,
40
+ knowledge_resource_search: z.object({ ...context, after: position, limit, ...filters, query: z.string().min(2).max(200) }).strict(),
41
+ knowledge_resource_window: z.object(context).strict(),
42
+ knowledge_resource_changes: z.object({ ...context, after: position, limit }).strict(),
43
+ knowledge_resource_counts: z.object({ ...context, after: position, limit }).strict(),
44
+ knowledge_resource_index_status: z.object(context).strict(),
45
+ knowledge_resource_media: ref.extend({ afterOrdinal: z.number().int().min(-1).safe().optional(), limit, documentRef: stableUriSchema.optional() }).strict(),
46
+ };
47
+ const count = z.number().int().nonnegative().safe(), cursor = z.string().max(4096).nullable(), item = resourceDirectoryItemSchema.nullable(), items = z.array(resourceDirectoryItemSchema).max(100);
48
+ const representation = z.object({ state: z.enum(['READY', 'UNSUPPORTED', 'MISSING', 'INTEGRITY_MISMATCH', 'DENIED']), format: z.enum(['JSON', 'BYTES']), transfer: z.enum(['BUFFERED_JSON', 'VERIFIED_STREAM', 'UNSUPPORTED']), contentHash: sha256Schema.nullable(), mediaType: z.string().min(1).max(256), byteLength: count.nullable(), methods: z.array(z.enum(['GET', 'HEAD', 'POST'])).max(3), range: z.enum(['SINGLE', 'NONE']), verification: z.literal('ON_READ'), verificationChunkBytes: count.nullable() }).strict();
49
+ export const resourceDataSchemas = {
50
+ knowledge_resource_list: z.object({ items, nextAfter: cursor }).strict(),
51
+ knowledge_resource_describe: z.object({ item, byteLength: count.nullable(), downloadUrl: z.string().max(8192).nullable() }).strict(),
52
+ knowledge_resource_read: z.object({ item, byteLength: count.nullable(), decision: rawRetrievalDecisionSchema, descriptor: rawContentDescriptorSchema.nullable(), delivery: z.enum(['INLINE_BASE64', 'DOWNLOAD', 'UNAVAILABLE']), contentBase64: z.string().max(43692).nullable(), downloadUrl: z.string().max(8192).nullable(), verification: z.enum(['VERIFIED', 'NOT_VERIFIED']) }).strict(),
53
+ knowledge_resource_capabilities: z.object({ item, materialAccess: rawRetrievalDecisionSchema, representation: representation.nullable() }).strict(),
54
+ knowledge_resource_search: z.object({ items, nextAfter: cursor, coverage: z.literal('INDEXED_DESCRIPTIONS_ONLY') }).strict(),
55
+ knowledge_resource_window: z.object({ headSeq: count, retainedThroughSeq: count, headCursor: z.string().max(4096), retentionCursor: z.string().max(4096), epoch: z.literal('TENANT_RESOURCE_V1') }).strict(),
56
+ knowledge_resource_changes: z.object({ items: z.array(z.object({ seq: count, eventType: z.string().min(1).max(128), artifactRef: stableUriSchema.nullable(), contentHash: sha256Schema.nullable(), routeId: z.string().max(128).nullable(), createdAt: z.string().datetime({ offset: true }) }).strict()).max(100), nextAfter: cursor }).strict(),
57
+ knowledge_resource_counts: z.object({ owned: count, granted: count, available: count, resourceTypes: z.array(z.object({ resourceType: materialResourceTypeSchema, total: count }).strict()).max(100), nextAfter: cursor, coverage: z.literal('CURRENT_AUTHORIZED_DIRECTORY') }).strict(),
58
+ knowledge_resource_index_status: z.object({ registered: count, indexed: count, unindexed: count, state: z.enum(['SYNCED_AS_OF_LAST_OBSERVATION', 'PARTIAL_BACKFILL']), canonicalInventory: z.literal('NOT_SCANNED'), coverage: z.literal('CURRENT_AUTHORIZED_DIRECTORY') }).strict(),
59
+ knowledge_resource_media: tenantMaterialDataSchemas.knowledge_material_media,
60
+ };
61
+ export const resourceEnvelopeSchema = z.object({ schemaVersion: z.literal(2), context: materialContextSchema, policy: materialAuthorityPolicySchema, data: z.unknown() }).strict().superRefine((value, ctx) => {
62
+ const c = value.context, expected = c.type === 'TENANT' ? `knowledge-tenant://tenant/${encodeURIComponent(c.tenantId)}` : `knowledge-project://${c.projectKey}/tenant/${encodeURIComponent(c.tenantId)}`;
63
+ if ((value.policy === 'TENANT_NATIVE') !== (c.type === 'TENANT') || (c.type === 'TENANT' ? c.tenantRef : c.projectRef) !== expected)
64
+ ctx.addIssue({ code: 'custom', path: ['context'], message: 'Context/policy identity mismatch' });
65
+ });
66
+ export const resourceToolInputSchemas = Object.fromEntries(Object.entries(resourceToolSchemas).map(([name, schema]) => [name, z.toJSONSchema(schema, { target: 'draft-07' })]));
67
+ export const resourceToolOutputSchemas = Object.fromEntries(Object.entries(resourceDataSchemas).map(([name, data]) => [name, z.toJSONSchema(resourceEnvelopeSchema.safeExtend({ data }), { target: 'draft-07' })]));
68
+ export const tenantResourceProviderSchema = tenantMaterialProviderSchema.extend({ schemaVersion: z.literal(16), materialSchemaVersion: z.literal(2), capabilities: z.tuple([z.literal('TENANT_RESOURCE_V1'), z.literal('TENANT_AUTHORITY_V1')]), legacyProviderEndpoint: stableUriSchema });
69
+ export const resourceHttpContractSchema = z.object({ schemaVersion: z.literal(2), context: materialContextSchema, policy: materialAuthorityPolicySchema, capabilities: z.tuple([z.literal('TENANT_RESOURCE_V1'), z.literal('TENANT_AUTHORITY_V1')]), callEndpoint: z.string().min(1).max(8192), fileEndpoint: z.string().min(1).max(8192), tools: z.array(z.string()).max(32), inlineMaxBytes: z.literal(32768), readBufferMaxBytes: z.literal(16777216), fileMethods: z.tuple([z.literal('GET'), z.literal('HEAD'), z.literal('POST')]), verificationChunkBytes: z.literal(65536), requestMaxBytes: z.literal(131072), resultMaxBytes: z.literal(524288) }).strict().superRefine((value, ctx) => { if (!resourceEnvelopeSchema.safeParse({ schemaVersion: 2, context: value.context, policy: value.policy, data: null }).success)
70
+ ctx.addIssue({ code: 'custom', path: ['context'], message: 'Context/policy identity mismatch' }); });
@@ -0,0 +1,298 @@
1
+ /** 租户原生不可变信封保留类型事实;不以项目占位或审核状态判断原文读取。 */
2
+ import { z } from 'zod';
3
+ export declare const tenantResourceFactsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
+ type: z.ZodLiteral<"ARTIFACT">;
5
+ metadata: z.ZodObject<{
6
+ artifactId: z.ZodString;
7
+ kind: z.ZodEnum<{
8
+ SIGNAL_GENERATION: "SIGNAL_GENERATION";
9
+ RESEARCH: "RESEARCH";
10
+ REVIEW: "REVIEW";
11
+ KNOWLEDGE: "KNOWLEDGE";
12
+ INSIGHT: "INSIGHT";
13
+ }>;
14
+ status: z.ZodEnum<{
15
+ GENERATED: "GENERATED";
16
+ DRAFT: "DRAFT";
17
+ READY_FOR_REVIEW: "READY_FOR_REVIEW";
18
+ REWORK_REQUIRED: "REWORK_REQUIRED";
19
+ APPROVED: "APPROVED";
20
+ REJECTED: "REJECTED";
21
+ SUPERSEDED: "SUPERSEDED";
22
+ }>;
23
+ version: z.ZodNumber;
24
+ title: z.ZodOptional<z.ZodString>;
25
+ observedAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
26
+ validUntil: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
27
+ evidenceRefs: z.ZodDefault<z.ZodArray<z.ZodString>>;
28
+ relatedRefs: z.ZodDefault<z.ZodArray<z.ZodString>>;
29
+ supersedesRef: z.ZodDefault<z.ZodNullable<z.ZodString>>;
30
+ sourceMaterialRefs: z.ZodOptional<z.ZodArray<z.ZodString>>;
31
+ }, z.core.$strict>;
32
+ }, z.core.$strict>, z.ZodObject<{
33
+ type: z.ZodLiteral<"EVIDENCE">;
34
+ metadata: z.ZodObject<{
35
+ observedAt: z.ZodISODateTime;
36
+ sourceIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
37
+ runtimeNodeId: z.ZodString;
38
+ request: z.ZodOptional<z.ZodObject<{
39
+ schemaVersion: z.ZodLiteral<1>;
40
+ method: z.ZodLiteral<"POST">;
41
+ bodyContentHash: z.ZodString;
42
+ bodyMediaType: z.ZodLiteral<"application/x-www-form-urlencoded">;
43
+ bodyByteLength: z.ZodNumber;
44
+ }, z.core.$strict>>;
45
+ sourceId: z.ZodString;
46
+ sourceRevisionRef: z.ZodOptional<z.ZodString>;
47
+ collectionBatchRef: z.ZodOptional<z.ZodString>;
48
+ reviewHints: z.ZodOptional<z.ZodObject<{
49
+ pageRanges: z.ZodDefault<z.ZodArray<z.ZodObject<{
50
+ startPage: z.ZodNumber;
51
+ endPage: z.ZodNumber;
52
+ }, z.core.$strict>>>;
53
+ timeRanges: z.ZodDefault<z.ZodArray<z.ZodObject<{
54
+ startMs: z.ZodNumber;
55
+ endMs: z.ZodNumber;
56
+ }, z.core.$strict>>>;
57
+ frameTimestampsMs: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
58
+ }, z.core.$strict>>;
59
+ evidenceId: z.ZodString;
60
+ collector: z.ZodObject<{
61
+ collectorId: z.ZodString;
62
+ version: z.ZodString;
63
+ }, z.core.$strict>;
64
+ canonicalUri: z.ZodOptional<z.ZodString>;
65
+ sourceSetRef: z.ZodOptional<z.ZodString>;
66
+ sourceItemId: z.ZodOptional<z.ZodString>;
67
+ collectionTaskId: z.ZodOptional<z.ZodString>;
68
+ parentEvidenceRef: z.ZodOptional<z.ZodString>;
69
+ }, z.core.$strict>;
70
+ }, z.core.$strict>, z.ZodObject<{
71
+ type: z.ZodLiteral<"REFERENCE">;
72
+ metadata: z.ZodObject<{
73
+ version: z.ZodNumber;
74
+ supersedesRef: z.ZodNullable<z.ZodString>;
75
+ effectiveFrom: z.ZodNullable<z.ZodISODateTime>;
76
+ effectiveUntil: z.ZodNullable<z.ZodISODateTime>;
77
+ authority: z.ZodString;
78
+ currentness: z.ZodObject<{
79
+ state: z.ZodEnum<{
80
+ DUE: "DUE";
81
+ CURRENT: "CURRENT";
82
+ STALE: "STALE";
83
+ UNAVAILABLE: "UNAVAILABLE";
84
+ NOT_COVERED: "NOT_COVERED";
85
+ }>;
86
+ action: z.ZodEnum<{
87
+ ALLOW: "ALLOW";
88
+ REVIEW_REQUIRED: "REVIEW_REQUIRED";
89
+ DENY: "DENY";
90
+ }>;
91
+ assessedAt: z.ZodISODateTime;
92
+ validUntil: z.ZodNullable<z.ZodISODateTime>;
93
+ }, z.core.$strict>;
94
+ jurisdiction: z.ZodNullable<z.ZodString>;
95
+ sourceRefs: z.ZodArray<z.ZodString>;
96
+ corpusKey: z.ZodString;
97
+ recordKey: z.ZodString;
98
+ recordType: z.ZodString;
99
+ digest: z.ZodString;
100
+ selectors: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
101
+ }, z.core.$strict>;
102
+ }, z.core.$strict>, z.ZodObject<{
103
+ type: z.ZodLiteral<"CARRIER">;
104
+ metadata: z.ZodObject<{
105
+ kind: z.ZodString;
106
+ title: z.ZodString;
107
+ summary: z.ZodString;
108
+ sourceRefs: z.ZodArray<z.ZodString>;
109
+ observedAt: z.ZodISODateTime;
110
+ }, z.core.$strict>;
111
+ }, z.core.$strict>], "type">;
112
+ export declare const tenantResourceOriginSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
113
+ type: z.ZodLiteral<"TENANT_AUTHOR">;
114
+ actor: z.ZodObject<{
115
+ tenantId: z.ZodString;
116
+ userId: z.ZodString;
117
+ agentId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
118
+ }, z.core.$strict>;
119
+ submittedAt: z.ZodISODateTime;
120
+ }, z.core.$strict>, z.ZodObject<{
121
+ type: z.ZodLiteral<"TENANT_SOURCE">;
122
+ sourceId: z.ZodString;
123
+ sourceRef: z.ZodString;
124
+ sourceRevisionRef: z.ZodString;
125
+ collector: z.ZodObject<{
126
+ collectorId: z.ZodString;
127
+ version: z.ZodString;
128
+ }, z.core.$strict>;
129
+ runtimeNodeId: z.ZodString;
130
+ observedAt: z.ZodISODateTime;
131
+ }, z.core.$strict>], "type">;
132
+ export declare const tenantResourceManifestSchema: z.ZodObject<{
133
+ schemaVersion: z.ZodLiteral<2>;
134
+ ownerTenantId: z.ZodString;
135
+ resourceId: z.ZodString;
136
+ resourceType: z.ZodString;
137
+ version: z.ZodNumber;
138
+ ref: z.ZodString;
139
+ identityRef: z.ZodString;
140
+ contentHash: z.ZodString;
141
+ byteLength: z.ZodNumber;
142
+ mediaType: z.ZodString;
143
+ access: z.ZodEnum<{
144
+ PUBLIC: "PUBLIC";
145
+ PUBLIC_METADATA: "PUBLIC_METADATA";
146
+ TENANT: "TENANT";
147
+ INTERNAL: "INTERNAL";
148
+ FDE_INTERNAL: "FDE_INTERNAL";
149
+ ACCESS_CONTROLLED: "ACCESS_CONTROLLED";
150
+ UNKNOWN: "UNKNOWN";
151
+ }>;
152
+ createdAt: z.ZodISODateTime;
153
+ origin: z.ZodDiscriminatedUnion<[z.ZodObject<{
154
+ type: z.ZodLiteral<"TENANT_AUTHOR">;
155
+ actor: z.ZodObject<{
156
+ tenantId: z.ZodString;
157
+ userId: z.ZodString;
158
+ agentId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
159
+ }, z.core.$strict>;
160
+ submittedAt: z.ZodISODateTime;
161
+ }, z.core.$strict>, z.ZodObject<{
162
+ type: z.ZodLiteral<"TENANT_SOURCE">;
163
+ sourceId: z.ZodString;
164
+ sourceRef: z.ZodString;
165
+ sourceRevisionRef: z.ZodString;
166
+ collector: z.ZodObject<{
167
+ collectorId: z.ZodString;
168
+ version: z.ZodString;
169
+ }, z.core.$strict>;
170
+ runtimeNodeId: z.ZodString;
171
+ observedAt: z.ZodISODateTime;
172
+ }, z.core.$strict>], "type">;
173
+ facts: z.ZodDiscriminatedUnion<[z.ZodObject<{
174
+ type: z.ZodLiteral<"ARTIFACT">;
175
+ metadata: z.ZodObject<{
176
+ artifactId: z.ZodString;
177
+ kind: z.ZodEnum<{
178
+ SIGNAL_GENERATION: "SIGNAL_GENERATION";
179
+ RESEARCH: "RESEARCH";
180
+ REVIEW: "REVIEW";
181
+ KNOWLEDGE: "KNOWLEDGE";
182
+ INSIGHT: "INSIGHT";
183
+ }>;
184
+ status: z.ZodEnum<{
185
+ GENERATED: "GENERATED";
186
+ DRAFT: "DRAFT";
187
+ READY_FOR_REVIEW: "READY_FOR_REVIEW";
188
+ REWORK_REQUIRED: "REWORK_REQUIRED";
189
+ APPROVED: "APPROVED";
190
+ REJECTED: "REJECTED";
191
+ SUPERSEDED: "SUPERSEDED";
192
+ }>;
193
+ version: z.ZodNumber;
194
+ title: z.ZodOptional<z.ZodString>;
195
+ observedAt: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
196
+ validUntil: z.ZodDefault<z.ZodNullable<z.ZodISODateTime>>;
197
+ evidenceRefs: z.ZodDefault<z.ZodArray<z.ZodString>>;
198
+ relatedRefs: z.ZodDefault<z.ZodArray<z.ZodString>>;
199
+ supersedesRef: z.ZodDefault<z.ZodNullable<z.ZodString>>;
200
+ sourceMaterialRefs: z.ZodOptional<z.ZodArray<z.ZodString>>;
201
+ }, z.core.$strict>;
202
+ }, z.core.$strict>, z.ZodObject<{
203
+ type: z.ZodLiteral<"EVIDENCE">;
204
+ metadata: z.ZodObject<{
205
+ observedAt: z.ZodISODateTime;
206
+ sourceIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
207
+ runtimeNodeId: z.ZodString;
208
+ request: z.ZodOptional<z.ZodObject<{
209
+ schemaVersion: z.ZodLiteral<1>;
210
+ method: z.ZodLiteral<"POST">;
211
+ bodyContentHash: z.ZodString;
212
+ bodyMediaType: z.ZodLiteral<"application/x-www-form-urlencoded">;
213
+ bodyByteLength: z.ZodNumber;
214
+ }, z.core.$strict>>;
215
+ sourceId: z.ZodString;
216
+ sourceRevisionRef: z.ZodOptional<z.ZodString>;
217
+ collectionBatchRef: z.ZodOptional<z.ZodString>;
218
+ reviewHints: z.ZodOptional<z.ZodObject<{
219
+ pageRanges: z.ZodDefault<z.ZodArray<z.ZodObject<{
220
+ startPage: z.ZodNumber;
221
+ endPage: z.ZodNumber;
222
+ }, z.core.$strict>>>;
223
+ timeRanges: z.ZodDefault<z.ZodArray<z.ZodObject<{
224
+ startMs: z.ZodNumber;
225
+ endMs: z.ZodNumber;
226
+ }, z.core.$strict>>>;
227
+ frameTimestampsMs: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
228
+ }, z.core.$strict>>;
229
+ evidenceId: z.ZodString;
230
+ collector: z.ZodObject<{
231
+ collectorId: z.ZodString;
232
+ version: z.ZodString;
233
+ }, z.core.$strict>;
234
+ canonicalUri: z.ZodOptional<z.ZodString>;
235
+ sourceSetRef: z.ZodOptional<z.ZodString>;
236
+ sourceItemId: z.ZodOptional<z.ZodString>;
237
+ collectionTaskId: z.ZodOptional<z.ZodString>;
238
+ parentEvidenceRef: z.ZodOptional<z.ZodString>;
239
+ }, z.core.$strict>;
240
+ }, z.core.$strict>, z.ZodObject<{
241
+ type: z.ZodLiteral<"REFERENCE">;
242
+ metadata: z.ZodObject<{
243
+ version: z.ZodNumber;
244
+ supersedesRef: z.ZodNullable<z.ZodString>;
245
+ effectiveFrom: z.ZodNullable<z.ZodISODateTime>;
246
+ effectiveUntil: z.ZodNullable<z.ZodISODateTime>;
247
+ authority: z.ZodString;
248
+ currentness: z.ZodObject<{
249
+ state: z.ZodEnum<{
250
+ DUE: "DUE";
251
+ CURRENT: "CURRENT";
252
+ STALE: "STALE";
253
+ UNAVAILABLE: "UNAVAILABLE";
254
+ NOT_COVERED: "NOT_COVERED";
255
+ }>;
256
+ action: z.ZodEnum<{
257
+ ALLOW: "ALLOW";
258
+ REVIEW_REQUIRED: "REVIEW_REQUIRED";
259
+ DENY: "DENY";
260
+ }>;
261
+ assessedAt: z.ZodISODateTime;
262
+ validUntil: z.ZodNullable<z.ZodISODateTime>;
263
+ }, z.core.$strict>;
264
+ jurisdiction: z.ZodNullable<z.ZodString>;
265
+ sourceRefs: z.ZodArray<z.ZodString>;
266
+ corpusKey: z.ZodString;
267
+ recordKey: z.ZodString;
268
+ recordType: z.ZodString;
269
+ digest: z.ZodString;
270
+ selectors: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
271
+ }, z.core.$strict>;
272
+ }, z.core.$strict>, z.ZodObject<{
273
+ type: z.ZodLiteral<"CARRIER">;
274
+ metadata: z.ZodObject<{
275
+ kind: z.ZodString;
276
+ title: z.ZodString;
277
+ summary: z.ZodString;
278
+ sourceRefs: z.ZodArray<z.ZodString>;
279
+ observedAt: z.ZodISODateTime;
280
+ }, z.core.$strict>;
281
+ }, z.core.$strict>], "type">;
282
+ }, z.core.$strict>;
283
+ export type TenantResourceManifest = z.infer<typeof tenantResourceManifestSchema>;
284
+ export type TenantResourceFacts = z.infer<typeof tenantResourceFactsSchema>;
285
+ export type TenantResourceOrigin = z.infer<typeof tenantResourceOriginSchema>;
286
+ export declare const tenantProjectionIntentSchema: z.ZodObject<{
287
+ schemaVersion: z.ZodLiteral<2>;
288
+ ref: z.ZodString;
289
+ manifestRevision: z.ZodString;
290
+ createdAt: z.ZodISODateTime;
291
+ }, z.core.$strict>;
292
+ export type TenantProjectionIntent = z.infer<typeof tenantProjectionIntentSchema>;
293
+ /** 存储、Catalog 与 Identity 共用同一 manifest 身份;undefined 等价于 JSON 省略。 */
294
+ export declare function tenantResourceManifestRevision(raw: TenantResourceManifest): string;
295
+ /** Reference 语义摘要与 CAS 字节摘要分开;只正规化集合字段,不改原始 payload 字节。 */
296
+ export declare function tenantReferenceRecordDigest(tenantId: string, access: unknown, metadata: Extract<TenantResourceFacts, {
297
+ type: 'REFERENCE';
298
+ }>['metadata'], payload: unknown): string;
@@ -0,0 +1,118 @@
1
+ /** 租户原生不可变信封保留类型事实;不以项目占位或审核状态判断原文读取。 */
2
+ import { z } from 'zod';
3
+ import { createHash } from 'node:crypto';
4
+ import { accessClassificationSchema, idSchema, isoDateTimeSchema, sha256Schema, stableUriSchema } from './common.js';
5
+ import { artifactManifestSchema } from './artifact.js';
6
+ import { evidenceRefSchema } from './evidence.js';
7
+ import { referenceCorpusSummarySchema } from './reference-record.js';
8
+ import { knowledgeActorContextSchema } from './project-intent.js';
9
+ import { materialResourceTypeSchema } from './material-carrier.js';
10
+ import { materialTenantIdSchema } from './material-context.js';
11
+ import { tenantResourceIdentitySchema, tenantResourceRefs, tenantStorageKey, tenantResourceRefSchema } from './resource-scope.js';
12
+ // 取原有字段验证器,旧 schema/DTO 原样保留;新信封的身份关系在下方集中验证。
13
+ const artifactFacts = z.object({ ...artifactManifestSchema.shape }).omit({ schemaVersion: true, projectKey: true, projectRef: true, ref: true, identityRef: true, contentHash: true, mediaType: true, byteLength: true, access: true, createdAt: true }).extend({ sourceMaterialRefs: z.array(stableUriSchema).max(256).optional() }).strict();
14
+ const evidenceFacts = z.object({ ...evidenceRefSchema.shape }).omit({ schemaVersion: true, projectKey: true, projectRef: true, recoveryProvenance: true, contentHash: true, mediaType: true, byteLength: true, access: true }).extend({ parentEvidenceRef: tenantResourceRefSchema.optional() }).strict();
15
+ const referenceFacts = z.object({ ...referenceCorpusSummarySchema.shape }).omit({ schemaVersion: true, projectKey: true, projectRef: true, recordRef: true, access: true }).strict();
16
+ export const tenantResourceFactsSchema = z.discriminatedUnion('type', [
17
+ z.object({ type: z.literal('ARTIFACT'), metadata: artifactFacts }).strict(),
18
+ z.object({ type: z.literal('EVIDENCE'), metadata: evidenceFacts }).strict(),
19
+ z.object({ type: z.literal('REFERENCE'), metadata: referenceFacts }).strict(),
20
+ z.object({ type: z.literal('CARRIER'), metadata: z.object({ kind: z.string().min(1).max(128), title: z.string().max(512), summary: z.string().max(1024), sourceRefs: z.array(stableUriSchema).min(1).max(128), observedAt: isoDateTimeSchema }).strict() }).strict(),
21
+ ]);
22
+ export const tenantResourceOriginSchema = z.discriminatedUnion('type', [
23
+ z.object({ type: z.literal('TENANT_AUTHOR'), actor: knowledgeActorContextSchema, submittedAt: isoDateTimeSchema }).strict(),
24
+ z.object({ type: z.literal('TENANT_SOURCE'), sourceId: idSchema, sourceRef: stableUriSchema, sourceRevisionRef: stableUriSchema, collector: evidenceRefSchema.shape.collector, runtimeNodeId: idSchema, observedAt: isoDateTimeSchema }).strict(),
25
+ ]);
26
+ export const tenantResourceManifestSchema = z.object({
27
+ schemaVersion: z.literal(2), ownerTenantId: materialTenantIdSchema,
28
+ resourceId: tenantResourceIdentitySchema.shape.resourceId, resourceType: materialResourceTypeSchema,
29
+ version: tenantResourceIdentitySchema.shape.version, ref: stableUriSchema, identityRef: stableUriSchema,
30
+ contentHash: sha256Schema, byteLength: z.number().int().nonnegative().safe(), mediaType: z.string().trim().min(1).max(256),
31
+ access: accessClassificationSchema, createdAt: isoDateTimeSchema,
32
+ origin: tenantResourceOriginSchema, facts: tenantResourceFactsSchema,
33
+ }).strict().superRefine((value, ctx) => {
34
+ const expected = tenantResourceRefs({ tenantId: value.ownerTenantId, resourceType: value.resourceType, resourceId: value.resourceId, version: value.version });
35
+ for (const name of ['ref', 'identityRef'])
36
+ if (value[name] !== expected[name])
37
+ ctx.addIssue({ code: 'custom', path: [name], message: 'Tenant resource identity mismatch' });
38
+ const kind = value.facts.type.toLowerCase();
39
+ if (value.facts.type === 'CARRIER' ? ['artifact', 'evidence', 'reference', 'media'].includes(value.resourceType) : value.resourceType !== kind)
40
+ ctx.addIssue({ code: 'custom', path: ['resourceType'], message: 'Resource type must retain its factual carrier' });
41
+ if (value.origin.type === 'TENANT_AUTHOR') {
42
+ if (value.origin.actor.tenantId !== value.ownerTenantId)
43
+ ctx.addIssue({ code: 'custom', path: ['origin'], message: 'Author must belong to the resource Tenant' });
44
+ }
45
+ else {
46
+ const prefix = `tenant-source://${tenantStorageKey(value.ownerTenantId)}/${encodeURIComponent(value.origin.sourceId)}`;
47
+ if (value.origin.sourceRef !== prefix || !value.origin.sourceRevisionRef.startsWith(prefix + '/v/') || !/^[a-f0-9]{64}$/.test(value.origin.sourceRevisionRef.slice(prefix.length + 3)))
48
+ ctx.addIssue({ code: 'custom', path: ['origin'], message: 'Source must retain exact Tenant/source/revision identity' });
49
+ }
50
+ if (value.facts.type === 'ARTIFACT') {
51
+ const m = value.facts.metadata;
52
+ if (m.artifactId !== value.resourceId || m.version !== value.version)
53
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Artifact identity/version mismatch' });
54
+ if (m.validUntil && m.observedAt && Date.parse(m.validUntil) < Date.parse(m.observedAt))
55
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Invalid Artifact validity interval' });
56
+ if (m.kind === 'SIGNAL_GENERATION' && (m.version !== 1 || m.status !== 'GENERATED') || ['KNOWLEDGE', 'INSIGHT'].includes(m.kind) && m.status === 'GENERATED')
57
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Invalid Artifact lifecycle' });
58
+ const previous = value.version > 1 ? tenantResourceRefs({ tenantId: value.ownerTenantId, resourceType: value.resourceType, resourceId: value.resourceId, version: value.version - 1 }).ref : null;
59
+ if (m.supersedesRef !== previous)
60
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Artifact must retain immediate predecessor' });
61
+ }
62
+ if (value.facts.type === 'EVIDENCE') {
63
+ const m = value.facts.metadata;
64
+ if (m.parentEvidenceRef) {
65
+ const parent = new URL(m.parentEvidenceRef);
66
+ if (parent.hostname !== tenantStorageKey(value.ownerTenantId) || !parent.pathname.startsWith('/evidence/') || m.parentEvidenceRef === value.ref)
67
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Media parent must be another native Tenant Evidence' });
68
+ }
69
+ if (m.evidenceId !== value.resourceId || value.version !== 1 || Boolean(m.sourceSetRef) !== Boolean(m.sourceItemId) || Boolean(m.collectionBatchRef) !== Boolean(m.collectionTaskId))
70
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Evidence identity/bindings mismatch' });
71
+ if (value.origin.type === 'TENANT_SOURCE' && (m.sourceId !== value.origin.sourceId || m.runtimeNodeId !== value.origin.runtimeNodeId || m.observedAt !== value.origin.observedAt || m.sourceRevisionRef !== value.origin.sourceRevisionRef || JSON.stringify(m.collector) !== JSON.stringify(value.origin.collector)))
72
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Evidence must preserve acquisition provenance' });
73
+ }
74
+ if (value.facts.type === 'REFERENCE') {
75
+ const m = value.facts.metadata;
76
+ if (m.version !== value.version || m.effectiveFrom && m.effectiveUntil && Date.parse(m.effectiveUntil) <= Date.parse(m.effectiveFrom))
77
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Reference version/validity mismatch' });
78
+ const previous = value.version > 1 ? tenantResourceRefs({ tenantId: value.ownerTenantId, resourceType: value.resourceType, resourceId: value.resourceId, version: value.version - 1 }).ref : null;
79
+ if (m.supersedesRef !== previous)
80
+ ctx.addIssue({ code: 'custom', path: ['facts'], message: 'Reference must retain immediate predecessor' });
81
+ }
82
+ });
83
+ export const tenantProjectionIntentSchema = z.object({ schemaVersion: z.literal(2), ref: tenantResourceRefSchema, manifestRevision: sha256Schema, createdAt: isoDateTimeSchema }).strict();
84
+ /** 存储、Catalog 与 Identity 共用同一 manifest 身份;undefined 等价于 JSON 省略。 */
85
+ export function tenantResourceManifestRevision(raw) {
86
+ const json = JSON.stringify(tenantResourceManifestSchema.parse(raw));
87
+ if (Buffer.byteLength(json + '\n') > 64 * 1024)
88
+ throw new Error('TENANT_RESOURCE_MANIFEST_TOO_LARGE');
89
+ const canonical = (value) => { if (value === null || typeof value !== 'object')
90
+ return JSON.stringify(value); if (Array.isArray(value))
91
+ return '[' + value.map(canonical).join(',') + ']'; const row = value; return '{' + Object.keys(row).sort().map(key => JSON.stringify(key) + ':' + canonical(row[key])).join(',') + '}'; };
92
+ return 'sha256:' + createHash('sha256').update(canonical(JSON.parse(json))).digest('hex');
93
+ }
94
+ /** Reference 语义摘要与 CAS 字节摘要分开;只正规化集合字段,不改原始 payload 字节。 */
95
+ export function tenantReferenceRecordDigest(tenantId, access, metadata, payload) {
96
+ const parsed = tenantResourceFactsSchema.parse({ type: 'REFERENCE', metadata });
97
+ if (parsed.type !== 'REFERENCE')
98
+ throw new Error('TENANT_REFERENCE_FACTS_REQUIRED');
99
+ const m = parsed.metadata, selectors = m.selectors ? Object.fromEntries(Object.keys(m.selectors).sort().map(key => [key, [...new Set(m.selectors[key])].sort()])) : undefined;
100
+ const basis = { tenantId: materialTenantIdSchema.parse(tenantId), corpusKey: m.corpusKey, recordKey: m.recordKey, recordType: m.recordType, access: accessClassificationSchema.parse(access), authority: m.authority, jurisdiction: m.jurisdiction, ...(selectors ? { selectors } : {}), sourceRefs: [...new Set(m.sourceRefs)].sort(), effectiveFrom: m.effectiveFrom, effectiveUntil: m.effectiveUntil, payload };
101
+ let nodes = 0;
102
+ const canonical = (value, depth = 0) => {
103
+ if (++nodes > 1_000_000 || depth > 64)
104
+ throw new Error('TENANT_REFERENCE_JSON_BUDGET_EXCEEDED');
105
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
106
+ return JSON.stringify(value);
107
+ if (typeof value === 'number' && Number.isFinite(value))
108
+ return JSON.stringify(value);
109
+ if (Array.isArray(value))
110
+ return '[' + value.map(item => canonical(item, depth + 1)).join(',') + ']';
111
+ if (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {
112
+ const row = value;
113
+ return '{' + Object.keys(row).sort().map(key => JSON.stringify(key) + ':' + canonical(row[key], depth + 1)).join(',') + '}';
114
+ }
115
+ throw new Error('TENANT_REFERENCE_JSON_INVALID');
116
+ };
117
+ return 'sha256:' + createHash('sha256').update(canonical(basis)).digest('hex');
118
+ }