@originals/sdk 1.2.0 → 1.4.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 (244) hide show
  1. package/package.json +1 -1
  2. package/src/did/DIDManager.ts +1 -1
  3. package/src/did/WebVHManager.ts +11 -2
  4. package/src/examples/create-module-original.ts +435 -0
  5. package/src/examples/full-lifecycle-flow.ts +514 -0
  6. package/src/examples/run.ts +59 -4
  7. package/src/index.ts +69 -3
  8. package/src/kinds/KindRegistry.ts +290 -0
  9. package/src/kinds/index.ts +74 -0
  10. package/src/kinds/types.ts +470 -0
  11. package/src/kinds/validators/AgentValidator.ts +257 -0
  12. package/src/kinds/validators/AppValidator.ts +211 -0
  13. package/src/kinds/validators/DatasetValidator.ts +242 -0
  14. package/src/kinds/validators/DocumentValidator.ts +311 -0
  15. package/src/kinds/validators/MediaValidator.ts +269 -0
  16. package/src/kinds/validators/ModuleValidator.ts +225 -0
  17. package/src/kinds/validators/base.ts +276 -0
  18. package/src/kinds/validators/index.ts +12 -0
  19. package/src/lifecycle/LifecycleManager.ts +909 -1
  20. package/src/resources/ResourceManager.ts +655 -0
  21. package/src/resources/index.ts +21 -0
  22. package/src/resources/types.ts +202 -0
  23. package/src/types/common.ts +1 -1
  24. package/src/vc/CredentialManager.ts +647 -2
  25. package/tests/integration/createTypedOriginal.test.ts +379 -0
  26. package/tests/performance/BatchOperations.perf.test.ts +2 -2
  27. package/tests/unit/kinds/KindRegistry.test.ts +329 -0
  28. package/tests/unit/kinds/types.test.ts +409 -0
  29. package/tests/unit/kinds/validators.test.ts +651 -0
  30. package/tests/unit/lifecycle/LifecycleManager.cleanapi.test.ts +441 -0
  31. package/tests/unit/resources/ResourceManager.test.ts +740 -0
  32. package/tests/unit/vc/CredentialManager.helpers.test.ts +527 -0
  33. package/.turbo/turbo-build.log +0 -1
  34. package/dist/adapters/FeeOracleMock.d.ts +0 -6
  35. package/dist/adapters/FeeOracleMock.js +0 -8
  36. package/dist/adapters/index.d.ts +0 -4
  37. package/dist/adapters/index.js +0 -4
  38. package/dist/adapters/providers/OrdHttpProvider.d.ts +0 -56
  39. package/dist/adapters/providers/OrdHttpProvider.js +0 -110
  40. package/dist/adapters/providers/OrdMockProvider.d.ts +0 -70
  41. package/dist/adapters/providers/OrdMockProvider.js +0 -75
  42. package/dist/adapters/types.d.ts +0 -71
  43. package/dist/adapters/types.js +0 -1
  44. package/dist/bitcoin/BitcoinManager.d.ts +0 -15
  45. package/dist/bitcoin/BitcoinManager.js +0 -262
  46. package/dist/bitcoin/BroadcastClient.d.ts +0 -30
  47. package/dist/bitcoin/BroadcastClient.js +0 -35
  48. package/dist/bitcoin/OrdinalsClient.d.ts +0 -21
  49. package/dist/bitcoin/OrdinalsClient.js +0 -105
  50. package/dist/bitcoin/PSBTBuilder.d.ts +0 -24
  51. package/dist/bitcoin/PSBTBuilder.js +0 -80
  52. package/dist/bitcoin/fee-calculation.d.ts +0 -14
  53. package/dist/bitcoin/fee-calculation.js +0 -31
  54. package/dist/bitcoin/providers/OrdNodeProvider.d.ts +0 -38
  55. package/dist/bitcoin/providers/OrdNodeProvider.js +0 -67
  56. package/dist/bitcoin/providers/OrdinalsProvider.d.ts +0 -33
  57. package/dist/bitcoin/providers/OrdinalsProvider.js +0 -50
  58. package/dist/bitcoin/providers/types.d.ts +0 -63
  59. package/dist/bitcoin/providers/types.js +0 -1
  60. package/dist/bitcoin/transactions/commit.d.ts +0 -89
  61. package/dist/bitcoin/transactions/commit.js +0 -311
  62. package/dist/bitcoin/transactions/index.d.ts +0 -7
  63. package/dist/bitcoin/transactions/index.js +0 -8
  64. package/dist/bitcoin/transfer.d.ts +0 -9
  65. package/dist/bitcoin/transfer.js +0 -26
  66. package/dist/bitcoin/utxo-selection.d.ts +0 -78
  67. package/dist/bitcoin/utxo-selection.js +0 -237
  68. package/dist/bitcoin/utxo.d.ts +0 -26
  69. package/dist/bitcoin/utxo.js +0 -78
  70. package/dist/contexts/credentials-v1.json +0 -195
  71. package/dist/contexts/credentials-v2-examples.json +0 -5
  72. package/dist/contexts/credentials-v2.json +0 -301
  73. package/dist/contexts/credentials.json +0 -195
  74. package/dist/contexts/data-integrity-v2.json +0 -81
  75. package/dist/contexts/dids.json +0 -57
  76. package/dist/contexts/ed255192020.json +0 -93
  77. package/dist/contexts/ordinals-plus.json +0 -23
  78. package/dist/contexts/originals.json +0 -22
  79. package/dist/core/OriginalsSDK.d.ts +0 -158
  80. package/dist/core/OriginalsSDK.js +0 -274
  81. package/dist/crypto/Multikey.d.ts +0 -30
  82. package/dist/crypto/Multikey.js +0 -149
  83. package/dist/crypto/Signer.d.ts +0 -21
  84. package/dist/crypto/Signer.js +0 -196
  85. package/dist/crypto/noble-init.d.ts +0 -18
  86. package/dist/crypto/noble-init.js +0 -106
  87. package/dist/did/BtcoDidResolver.d.ts +0 -57
  88. package/dist/did/BtcoDidResolver.js +0 -166
  89. package/dist/did/DIDManager.d.ts +0 -101
  90. package/dist/did/DIDManager.js +0 -493
  91. package/dist/did/Ed25519Verifier.d.ts +0 -30
  92. package/dist/did/Ed25519Verifier.js +0 -59
  93. package/dist/did/KeyManager.d.ts +0 -17
  94. package/dist/did/KeyManager.js +0 -207
  95. package/dist/did/WebVHManager.d.ts +0 -100
  96. package/dist/did/WebVHManager.js +0 -304
  97. package/dist/did/createBtcoDidDocument.d.ts +0 -10
  98. package/dist/did/createBtcoDidDocument.js +0 -42
  99. package/dist/did/providers/OrdinalsClientProviderAdapter.d.ts +0 -23
  100. package/dist/did/providers/OrdinalsClientProviderAdapter.js +0 -51
  101. package/dist/events/EventEmitter.d.ts +0 -115
  102. package/dist/events/EventEmitter.js +0 -198
  103. package/dist/events/index.d.ts +0 -7
  104. package/dist/events/index.js +0 -6
  105. package/dist/events/types.d.ts +0 -286
  106. package/dist/events/types.js +0 -9
  107. package/dist/examples/basic-usage.d.ts +0 -3
  108. package/dist/examples/basic-usage.js +0 -62
  109. package/dist/examples/run.d.ts +0 -1
  110. package/dist/examples/run.js +0 -4
  111. package/dist/index.d.ts +0 -39
  112. package/dist/index.js +0 -47
  113. package/dist/lifecycle/BatchOperations.d.ts +0 -147
  114. package/dist/lifecycle/BatchOperations.js +0 -251
  115. package/dist/lifecycle/LifecycleManager.d.ts +0 -116
  116. package/dist/lifecycle/LifecycleManager.js +0 -971
  117. package/dist/lifecycle/OriginalsAsset.d.ts +0 -164
  118. package/dist/lifecycle/OriginalsAsset.js +0 -380
  119. package/dist/lifecycle/ProvenanceQuery.d.ts +0 -126
  120. package/dist/lifecycle/ProvenanceQuery.js +0 -220
  121. package/dist/lifecycle/ResourceVersioning.d.ts +0 -73
  122. package/dist/lifecycle/ResourceVersioning.js +0 -127
  123. package/dist/migration/MigrationManager.d.ts +0 -86
  124. package/dist/migration/MigrationManager.js +0 -412
  125. package/dist/migration/audit/AuditLogger.d.ts +0 -51
  126. package/dist/migration/audit/AuditLogger.js +0 -156
  127. package/dist/migration/checkpoint/CheckpointManager.d.ts +0 -31
  128. package/dist/migration/checkpoint/CheckpointManager.js +0 -96
  129. package/dist/migration/checkpoint/CheckpointStorage.d.ts +0 -26
  130. package/dist/migration/checkpoint/CheckpointStorage.js +0 -89
  131. package/dist/migration/index.d.ts +0 -22
  132. package/dist/migration/index.js +0 -27
  133. package/dist/migration/operations/BaseMigration.d.ts +0 -48
  134. package/dist/migration/operations/BaseMigration.js +0 -83
  135. package/dist/migration/operations/PeerToBtcoMigration.d.ts +0 -25
  136. package/dist/migration/operations/PeerToBtcoMigration.js +0 -67
  137. package/dist/migration/operations/PeerToWebvhMigration.d.ts +0 -19
  138. package/dist/migration/operations/PeerToWebvhMigration.js +0 -46
  139. package/dist/migration/operations/WebvhToBtcoMigration.d.ts +0 -25
  140. package/dist/migration/operations/WebvhToBtcoMigration.js +0 -67
  141. package/dist/migration/rollback/RollbackManager.d.ts +0 -29
  142. package/dist/migration/rollback/RollbackManager.js +0 -146
  143. package/dist/migration/state/StateMachine.d.ts +0 -25
  144. package/dist/migration/state/StateMachine.js +0 -76
  145. package/dist/migration/state/StateTracker.d.ts +0 -36
  146. package/dist/migration/state/StateTracker.js +0 -123
  147. package/dist/migration/types.d.ts +0 -306
  148. package/dist/migration/types.js +0 -33
  149. package/dist/migration/validation/BitcoinValidator.d.ts +0 -13
  150. package/dist/migration/validation/BitcoinValidator.js +0 -83
  151. package/dist/migration/validation/CredentialValidator.d.ts +0 -13
  152. package/dist/migration/validation/CredentialValidator.js +0 -46
  153. package/dist/migration/validation/DIDCompatibilityValidator.d.ts +0 -16
  154. package/dist/migration/validation/DIDCompatibilityValidator.js +0 -127
  155. package/dist/migration/validation/LifecycleValidator.d.ts +0 -10
  156. package/dist/migration/validation/LifecycleValidator.js +0 -52
  157. package/dist/migration/validation/StorageValidator.d.ts +0 -10
  158. package/dist/migration/validation/StorageValidator.js +0 -65
  159. package/dist/migration/validation/ValidationPipeline.d.ts +0 -29
  160. package/dist/migration/validation/ValidationPipeline.js +0 -180
  161. package/dist/storage/LocalStorageAdapter.d.ts +0 -11
  162. package/dist/storage/LocalStorageAdapter.js +0 -53
  163. package/dist/storage/MemoryStorageAdapter.d.ts +0 -6
  164. package/dist/storage/MemoryStorageAdapter.js +0 -21
  165. package/dist/storage/StorageAdapter.d.ts +0 -16
  166. package/dist/storage/StorageAdapter.js +0 -1
  167. package/dist/storage/index.d.ts +0 -2
  168. package/dist/storage/index.js +0 -2
  169. package/dist/types/bitcoin.d.ts +0 -84
  170. package/dist/types/bitcoin.js +0 -1
  171. package/dist/types/common.d.ts +0 -82
  172. package/dist/types/common.js +0 -1
  173. package/dist/types/credentials.d.ts +0 -75
  174. package/dist/types/credentials.js +0 -1
  175. package/dist/types/did.d.ts +0 -26
  176. package/dist/types/did.js +0 -1
  177. package/dist/types/index.d.ts +0 -5
  178. package/dist/types/index.js +0 -5
  179. package/dist/types/network.d.ts +0 -78
  180. package/dist/types/network.js +0 -145
  181. package/dist/utils/EventLogger.d.ts +0 -71
  182. package/dist/utils/EventLogger.js +0 -232
  183. package/dist/utils/Logger.d.ts +0 -106
  184. package/dist/utils/Logger.js +0 -257
  185. package/dist/utils/MetricsCollector.d.ts +0 -110
  186. package/dist/utils/MetricsCollector.js +0 -264
  187. package/dist/utils/bitcoin-address.d.ts +0 -38
  188. package/dist/utils/bitcoin-address.js +0 -113
  189. package/dist/utils/cbor.d.ts +0 -2
  190. package/dist/utils/cbor.js +0 -9
  191. package/dist/utils/encoding.d.ts +0 -37
  192. package/dist/utils/encoding.js +0 -120
  193. package/dist/utils/hash.d.ts +0 -1
  194. package/dist/utils/hash.js +0 -5
  195. package/dist/utils/retry.d.ts +0 -10
  196. package/dist/utils/retry.js +0 -35
  197. package/dist/utils/satoshi-validation.d.ts +0 -60
  198. package/dist/utils/satoshi-validation.js +0 -156
  199. package/dist/utils/serialization.d.ts +0 -14
  200. package/dist/utils/serialization.js +0 -76
  201. package/dist/utils/telemetry.d.ts +0 -17
  202. package/dist/utils/telemetry.js +0 -24
  203. package/dist/utils/validation.d.ts +0 -5
  204. package/dist/utils/validation.js +0 -98
  205. package/dist/vc/CredentialManager.d.ts +0 -22
  206. package/dist/vc/CredentialManager.js +0 -227
  207. package/dist/vc/Issuer.d.ts +0 -27
  208. package/dist/vc/Issuer.js +0 -70
  209. package/dist/vc/Verifier.d.ts +0 -16
  210. package/dist/vc/Verifier.js +0 -50
  211. package/dist/vc/cryptosuites/bbs.d.ts +0 -44
  212. package/dist/vc/cryptosuites/bbs.js +0 -213
  213. package/dist/vc/cryptosuites/bbsSimple.d.ts +0 -9
  214. package/dist/vc/cryptosuites/bbsSimple.js +0 -12
  215. package/dist/vc/cryptosuites/eddsa.d.ts +0 -30
  216. package/dist/vc/cryptosuites/eddsa.js +0 -81
  217. package/dist/vc/documentLoader.d.ts +0 -16
  218. package/dist/vc/documentLoader.js +0 -59
  219. package/dist/vc/proofs/data-integrity.d.ts +0 -21
  220. package/dist/vc/proofs/data-integrity.js +0 -15
  221. package/dist/vc/utils/jsonld.d.ts +0 -2
  222. package/dist/vc/utils/jsonld.js +0 -15
  223. package/test/logs/did_webvh_QmNTn9Kkp8dQ75WrF9xqJ2kuDp9QhKc3aPiERRMj8XoTBN_example_com.jsonl +0 -1
  224. package/test/logs/did_webvh_QmNu4MNr8Lr5txx5gYNhuhZDchXsZEu3hJXKYuphpWTPDp_example_com_users_etc_passwd.jsonl +0 -1
  225. package/test/logs/did_webvh_QmR9MrGZACzjKETA8SBRNCKG11HxU85c4bVR2qN5eDCfsD_example_com.jsonl +0 -1
  226. package/test/logs/did_webvh_QmUc5suaqRM2P4nrXxZwqYMfqzhdMqjuL7oJaJbEpCQVCd_example_com_users_etc_passwd.jsonl +0 -1
  227. package/test/logs/did_webvh_QmUkiB2RCV2VZ1RTXsCebWN25Eiy9TLvpzDWAJNjhgvB4X_example_com_etc_passwd.jsonl +0 -1
  228. package/test/logs/did_webvh_QmUoRTe8UMwpAQXZSAW7pjAgZK1tq2X3C6Kfxq3UXGcaGy_example_com_secret.jsonl +0 -1
  229. package/test/logs/did_webvh_QmWWot3chx1t6KwTmcE5i2FeDZ5JMkQw3qXycsKDVmJ9Be_example_com_users_alice.jsonl +0 -1
  230. package/test/logs/did_webvh_QmWvVgALL5kjZdpgR7KZay7J8UiiUr834kkRmWeFAxjAuC_example_com_users_etc_passwd.jsonl +0 -1
  231. package/test/logs/did_webvh_QmWwaRQHUZAFcKihFC6xR6tRTTrQhHPTku6azf1egWbpy1_example_com_users_alice.jsonl +0 -1
  232. package/test/logs/did_webvh_QmXJLtkz23r7AozbtXsZMKWnVU6rd38CkVtjdWuATU3Yp6_example_com_users_alice123_profile.jsonl +0 -1
  233. package/test/logs/did_webvh_QmYsce448po14oDE1wXbyaP6wY9HQgHSKLwdezn1k577SF_example_com_my_org_user_name_test_123.jsonl +0 -1
  234. package/test/logs/did_webvh_QmZBeNzzqajxdfwcDUPZ4P8C5YSXyRztrAwmPiKuKUxmAK_example_com.jsonl +0 -1
  235. package/test/logs/did_webvh_QmZhJsqxizwVbRtqCUkmE6XQunSxtxMt3gbTYadVBNAaEq_example_com.jsonl +0 -1
  236. package/test/logs/did_webvh_QmZk7NHU2D57RzzbMq4tWW9gBa9AqtVTWfiRM6RFdwGVj2_example_com.jsonl +0 -1
  237. package/test/logs/did_webvh_QmZshSXp9w8ovH62zGGBS1b5pGGPsuYiu1VQ935sga2hWF_example_com_level1_level2.jsonl +0 -1
  238. package/test/logs/did_webvh_QmbWAmw7HQL7vKJyCsctZihXf1rmT4sGvggKCPKWcUWjw1_example_com.jsonl +0 -1
  239. package/test/logs/did_webvh_QmbdLUMbYs3juR39TLB6hhrFWLcNg45ybUzeBJCS1MhCh1_example_com_C_Windows_System32.jsonl +0 -1
  240. package/test/logs/did_webvh_QmcaQ1Ma4gkSbae85aCm8Mv4rvdT2Sb2RR3JzYwrm5XBq8_example_com_etc_passwd.jsonl +0 -1
  241. package/test/logs/did_webvh_QmcbA7WQhsBqZSoDpKJHjV8Q5o53h8vmgJhQfo6rqTY5ho_example_com.jsonl +0 -1
  242. package/test/logs/did_webvh_Qmdy8uWr2gkUJrXsThynAug3DASTWwb3onEj89LKmMGZYB_example_com.jsonl +0 -1
  243. package/tests/e2e/README.md +0 -97
  244. package/tests/e2e/example.spec.ts +0 -78
@@ -0,0 +1,651 @@
1
+ /**
2
+ * Tests for Kind validators
3
+ */
4
+
5
+ import { describe, expect, it } from 'bun:test';
6
+ import {
7
+ OriginalKind,
8
+ type OriginalManifest,
9
+ type AppManifest,
10
+ type ModuleManifest,
11
+ type DatasetManifest,
12
+ type AgentManifest,
13
+ type MediaManifest,
14
+ type DocumentManifest,
15
+ AppValidator,
16
+ ModuleValidator,
17
+ DatasetValidator,
18
+ AgentValidator,
19
+ MediaValidator,
20
+ DocumentValidator,
21
+ ValidationUtils,
22
+ } from '../../../src/kinds';
23
+
24
+ // Helper to create a minimal valid resource
25
+ const createResource = (id: string, type = 'code', contentType = 'application/javascript') => ({
26
+ id,
27
+ type,
28
+ contentType,
29
+ hash: 'abcdef1234567890',
30
+ });
31
+
32
+ describe('ValidationUtils', () => {
33
+ describe('isValidSemver', () => {
34
+ it('should accept valid semver versions', () => {
35
+ expect(ValidationUtils.isValidSemver('1.0.0')).toBe(true);
36
+ expect(ValidationUtils.isValidSemver('0.0.1')).toBe(true);
37
+ expect(ValidationUtils.isValidSemver('10.20.30')).toBe(true);
38
+ expect(ValidationUtils.isValidSemver('1.0.0-alpha')).toBe(true);
39
+ expect(ValidationUtils.isValidSemver('1.0.0-beta.1')).toBe(true);
40
+ expect(ValidationUtils.isValidSemver('1.0.0+build.123')).toBe(true);
41
+ });
42
+
43
+ it('should reject invalid semver versions', () => {
44
+ expect(ValidationUtils.isValidSemver('1.0')).toBe(false);
45
+ expect(ValidationUtils.isValidSemver('1')).toBe(false);
46
+ expect(ValidationUtils.isValidSemver('v1.0.0')).toBe(false);
47
+ expect(ValidationUtils.isValidSemver('1.0.0.0')).toBe(false);
48
+ expect(ValidationUtils.isValidSemver('invalid')).toBe(false);
49
+ });
50
+ });
51
+
52
+ describe('isValidDID', () => {
53
+ it('should accept valid DIDs', () => {
54
+ expect(ValidationUtils.isValidDID('did:peer:123abc')).toBe(true);
55
+ expect(ValidationUtils.isValidDID('did:webvh:example.com:user')).toBe(true);
56
+ expect(ValidationUtils.isValidDID('did:btco:12345')).toBe(true);
57
+ });
58
+
59
+ it('should reject invalid DIDs', () => {
60
+ expect(ValidationUtils.isValidDID('not-a-did')).toBe(false);
61
+ expect(ValidationUtils.isValidDID('did:')).toBe(false);
62
+ expect(ValidationUtils.isValidDID('did:method:')).toBe(false);
63
+ });
64
+ });
65
+
66
+ describe('isValidMimeType', () => {
67
+ it('should accept valid MIME types', () => {
68
+ expect(ValidationUtils.isValidMimeType('application/json')).toBe(true);
69
+ expect(ValidationUtils.isValidMimeType('text/plain')).toBe(true);
70
+ expect(ValidationUtils.isValidMimeType('image/png')).toBe(true);
71
+ expect(ValidationUtils.isValidMimeType('application/octet-stream')).toBe(true);
72
+ });
73
+
74
+ it('should reject invalid MIME types', () => {
75
+ expect(ValidationUtils.isValidMimeType('json')).toBe(false);
76
+ expect(ValidationUtils.isValidMimeType('application')).toBe(false);
77
+ expect(ValidationUtils.isValidMimeType('/json')).toBe(false);
78
+ });
79
+ });
80
+
81
+ describe('merge', () => {
82
+ it('should merge validation results', () => {
83
+ const result1 = ValidationUtils.failure([ValidationUtils.error('E1', 'Error 1')]);
84
+ const result2 = ValidationUtils.success([ValidationUtils.warning('W1', 'Warning 1')]);
85
+
86
+ const merged = ValidationUtils.merge(result1, result2);
87
+
88
+ expect(merged.isValid).toBe(false);
89
+ expect(merged.errors.length).toBe(1);
90
+ expect(merged.warnings.length).toBe(1);
91
+ });
92
+ });
93
+ });
94
+
95
+ describe('AppValidator', () => {
96
+ const validator = new AppValidator();
97
+
98
+ it('should validate a minimal valid app manifest', () => {
99
+ const manifest: AppManifest = {
100
+ kind: OriginalKind.App,
101
+ name: 'my-app',
102
+ version: '1.0.0',
103
+ resources: [createResource('index.js')],
104
+ metadata: {
105
+ runtime: 'node',
106
+ entrypoint: 'index.js',
107
+ }
108
+ };
109
+
110
+ const result = validator.validate(manifest);
111
+ expect(result.isValid).toBe(true);
112
+ expect(result.errors.length).toBe(0);
113
+ });
114
+
115
+ it('should fail when runtime is missing', () => {
116
+ const manifest = {
117
+ kind: OriginalKind.App,
118
+ name: 'my-app',
119
+ version: '1.0.0',
120
+ resources: [createResource('index.js')],
121
+ metadata: {
122
+ entrypoint: 'index.js',
123
+ } as any
124
+ } as AppManifest;
125
+
126
+ const result = validator.validate(manifest);
127
+ expect(result.isValid).toBe(false);
128
+ expect(result.errors.some(e => e.code === 'MISSING_RUNTIME')).toBe(true);
129
+ });
130
+
131
+ it('should fail when entrypoint is missing', () => {
132
+ const manifest = {
133
+ kind: OriginalKind.App,
134
+ name: 'my-app',
135
+ version: '1.0.0',
136
+ resources: [createResource('index.js')],
137
+ metadata: {
138
+ runtime: 'node',
139
+ } as any
140
+ } as AppManifest;
141
+
142
+ const result = validator.validate(manifest);
143
+ expect(result.isValid).toBe(false);
144
+ expect(result.errors.some(e => e.code === 'MISSING_ENTRYPOINT')).toBe(true);
145
+ });
146
+
147
+ it('should warn for unknown runtime', () => {
148
+ const manifest: AppManifest = {
149
+ kind: OriginalKind.App,
150
+ name: 'my-app',
151
+ version: '1.0.0',
152
+ resources: [createResource('index.js')],
153
+ metadata: {
154
+ runtime: 'exotic-runtime',
155
+ entrypoint: 'index.js',
156
+ }
157
+ };
158
+
159
+ const result = validator.validate(manifest);
160
+ expect(result.isValid).toBe(true);
161
+ expect(result.warnings.some(w => w.code === 'UNKNOWN_RUNTIME')).toBe(true);
162
+ });
163
+
164
+ it('should validate platforms array', () => {
165
+ const manifest: AppManifest = {
166
+ kind: OriginalKind.App,
167
+ name: 'my-app',
168
+ version: '1.0.0',
169
+ resources: [createResource('index.js')],
170
+ metadata: {
171
+ runtime: 'node',
172
+ entrypoint: 'index.js',
173
+ platforms: ['linux', 'darwin', 'invalid' as any],
174
+ }
175
+ };
176
+
177
+ const result = validator.validate(manifest);
178
+ expect(result.isValid).toBe(false);
179
+ expect(result.errors.some(e => e.code === 'INVALID_PLATFORM')).toBe(true);
180
+ });
181
+ });
182
+
183
+ describe('ModuleValidator', () => {
184
+ const validator = new ModuleValidator();
185
+
186
+ it('should validate a minimal valid module manifest', () => {
187
+ const manifest: ModuleManifest = {
188
+ kind: OriginalKind.Module,
189
+ name: 'my-module',
190
+ version: '1.0.0',
191
+ resources: [createResource('index.js')],
192
+ metadata: {
193
+ format: 'esm',
194
+ main: 'index.js',
195
+ }
196
+ };
197
+
198
+ const result = validator.validate(manifest);
199
+ expect(result.isValid).toBe(true);
200
+ });
201
+
202
+ it('should fail for invalid module format', () => {
203
+ const manifest = {
204
+ kind: OriginalKind.Module,
205
+ name: 'my-module',
206
+ version: '1.0.0',
207
+ resources: [createResource('index.js')],
208
+ metadata: {
209
+ format: 'invalid' as any,
210
+ main: 'index.js',
211
+ }
212
+ } as ModuleManifest;
213
+
214
+ const result = validator.validate(manifest);
215
+ expect(result.isValid).toBe(false);
216
+ expect(result.errors.some(e => e.code === 'INVALID_FORMAT')).toBe(true);
217
+ });
218
+
219
+ it('should fail when main is missing', () => {
220
+ const manifest = {
221
+ kind: OriginalKind.Module,
222
+ name: 'my-module',
223
+ version: '1.0.0',
224
+ resources: [createResource('index.js')],
225
+ metadata: {
226
+ format: 'esm',
227
+ } as any
228
+ } as ModuleManifest;
229
+
230
+ const result = validator.validate(manifest);
231
+ expect(result.isValid).toBe(false);
232
+ expect(result.errors.some(e => e.code === 'MISSING_MAIN')).toBe(true);
233
+ });
234
+
235
+ it('should warn when types are missing', () => {
236
+ const manifest: ModuleManifest = {
237
+ kind: OriginalKind.Module,
238
+ name: 'my-module',
239
+ version: '1.0.0',
240
+ resources: [createResource('index.js')],
241
+ metadata: {
242
+ format: 'esm',
243
+ main: 'index.js',
244
+ }
245
+ };
246
+
247
+ const result = validator.validate(manifest);
248
+ expect(result.warnings.some(w => w.code === 'MISSING_TYPES')).toBe(true);
249
+ });
250
+ });
251
+
252
+ describe('DatasetValidator', () => {
253
+ const validator = new DatasetValidator();
254
+
255
+ it('should validate a minimal valid dataset manifest', () => {
256
+ const manifest: DatasetManifest = {
257
+ kind: OriginalKind.Dataset,
258
+ name: 'my-dataset',
259
+ version: '1.0.0',
260
+ resources: [createResource('data.json', 'data', 'application/json')],
261
+ metadata: {
262
+ format: 'json',
263
+ schema: { type: 'object' },
264
+ }
265
+ };
266
+
267
+ const result = validator.validate(manifest);
268
+ expect(result.isValid).toBe(true);
269
+ });
270
+
271
+ it('should fail when schema is missing', () => {
272
+ const manifest = {
273
+ kind: OriginalKind.Dataset,
274
+ name: 'my-dataset',
275
+ version: '1.0.0',
276
+ resources: [createResource('data.json', 'data', 'application/json')],
277
+ metadata: {
278
+ format: 'json',
279
+ } as any
280
+ } as DatasetManifest;
281
+
282
+ const result = validator.validate(manifest);
283
+ expect(result.isValid).toBe(false);
284
+ expect(result.errors.some(e => e.code === 'MISSING_SCHEMA')).toBe(true);
285
+ });
286
+
287
+ it('should validate columns uniqueness', () => {
288
+ const manifest: DatasetManifest = {
289
+ kind: OriginalKind.Dataset,
290
+ name: 'my-dataset',
291
+ version: '1.0.0',
292
+ resources: [createResource('data.csv', 'data', 'text/csv')],
293
+ metadata: {
294
+ format: 'csv',
295
+ schema: {},
296
+ columns: [
297
+ { name: 'id', type: 'string' },
298
+ { name: 'id', type: 'string' }, // duplicate
299
+ ]
300
+ }
301
+ };
302
+
303
+ const result = validator.validate(manifest);
304
+ expect(result.isValid).toBe(false);
305
+ expect(result.errors.some(e => e.code === 'DUPLICATE_COLUMN')).toBe(true);
306
+ });
307
+
308
+ it('should validate privacy enum', () => {
309
+ const manifest: DatasetManifest = {
310
+ kind: OriginalKind.Dataset,
311
+ name: 'my-dataset',
312
+ version: '1.0.0',
313
+ resources: [createResource('data.json', 'data', 'application/json')],
314
+ metadata: {
315
+ format: 'json',
316
+ schema: {},
317
+ privacy: 'invalid' as any,
318
+ }
319
+ };
320
+
321
+ const result = validator.validate(manifest);
322
+ expect(result.isValid).toBe(false);
323
+ expect(result.errors.some(e => e.code === 'INVALID_PRIVACY')).toBe(true);
324
+ });
325
+ });
326
+
327
+ describe('AgentValidator', () => {
328
+ const validator = new AgentValidator();
329
+
330
+ it('should validate a minimal valid agent manifest', () => {
331
+ const manifest: AgentManifest = {
332
+ kind: OriginalKind.Agent,
333
+ name: 'my-agent',
334
+ version: '1.0.0',
335
+ resources: [createResource('config.json', 'config', 'application/json')],
336
+ metadata: {
337
+ capabilities: ['text-generation'],
338
+ }
339
+ };
340
+
341
+ const result = validator.validate(manifest);
342
+ expect(result.isValid).toBe(true);
343
+ });
344
+
345
+ it('should fail when capabilities is empty', () => {
346
+ const manifest: AgentManifest = {
347
+ kind: OriginalKind.Agent,
348
+ name: 'my-agent',
349
+ version: '1.0.0',
350
+ resources: [createResource('config.json', 'config', 'application/json')],
351
+ metadata: {
352
+ capabilities: [],
353
+ }
354
+ };
355
+
356
+ const result = validator.validate(manifest);
357
+ expect(result.isValid).toBe(false);
358
+ expect(result.errors.some(e => e.code === 'EMPTY_CAPABILITIES')).toBe(true);
359
+ });
360
+
361
+ it('should validate memory type', () => {
362
+ const manifest: AgentManifest = {
363
+ kind: OriginalKind.Agent,
364
+ name: 'my-agent',
365
+ version: '1.0.0',
366
+ resources: [createResource('config.json', 'config', 'application/json')],
367
+ metadata: {
368
+ capabilities: ['chat'],
369
+ memory: {
370
+ type: 'invalid' as any,
371
+ }
372
+ }
373
+ };
374
+
375
+ const result = validator.validate(manifest);
376
+ expect(result.isValid).toBe(false);
377
+ expect(result.errors.some(e => e.code === 'INVALID_MEMORY_TYPE')).toBe(true);
378
+ });
379
+
380
+ it('should validate tools structure', () => {
381
+ const manifest: AgentManifest = {
382
+ kind: OriginalKind.Agent,
383
+ name: 'my-agent',
384
+ version: '1.0.0',
385
+ resources: [createResource('config.json', 'config', 'application/json')],
386
+ metadata: {
387
+ capabilities: ['function-calling'],
388
+ tools: [
389
+ { name: 'search', description: 'Search the web' },
390
+ { name: '', description: 'Invalid tool' }, // missing name
391
+ ]
392
+ }
393
+ };
394
+
395
+ const result = validator.validate(manifest);
396
+ expect(result.isValid).toBe(false);
397
+ expect(result.errors.some(e => e.code === 'MISSING_TOOL_NAME')).toBe(true);
398
+ });
399
+ });
400
+
401
+ describe('MediaValidator', () => {
402
+ const validator = new MediaValidator();
403
+
404
+ it('should validate a minimal valid image manifest', () => {
405
+ const manifest: MediaManifest = {
406
+ kind: OriginalKind.Media,
407
+ name: 'my-image',
408
+ version: '1.0.0',
409
+ resources: [createResource('image.png', 'image', 'image/png')],
410
+ metadata: {
411
+ mediaType: 'image',
412
+ mimeType: 'image/png',
413
+ }
414
+ };
415
+
416
+ const result = validator.validate(manifest);
417
+ expect(result.isValid).toBe(true);
418
+ });
419
+
420
+ it('should fail for invalid media type', () => {
421
+ const manifest: MediaManifest = {
422
+ kind: OriginalKind.Media,
423
+ name: 'my-media',
424
+ version: '1.0.0',
425
+ resources: [createResource('file.bin', 'data', 'application/octet-stream')],
426
+ metadata: {
427
+ mediaType: 'invalid' as any,
428
+ mimeType: 'application/octet-stream',
429
+ }
430
+ };
431
+
432
+ const result = validator.validate(manifest);
433
+ expect(result.isValid).toBe(false);
434
+ expect(result.errors.some(e => e.code === 'INVALID_MEDIA_TYPE')).toBe(true);
435
+ });
436
+
437
+ it('should validate dimensions for images', () => {
438
+ const manifest: MediaManifest = {
439
+ kind: OriginalKind.Media,
440
+ name: 'my-image',
441
+ version: '1.0.0',
442
+ resources: [createResource('image.png', 'image', 'image/png')],
443
+ metadata: {
444
+ mediaType: 'image',
445
+ mimeType: 'image/png',
446
+ dimensions: {
447
+ width: -100, // invalid
448
+ height: 100,
449
+ }
450
+ }
451
+ };
452
+
453
+ const result = validator.validate(manifest);
454
+ expect(result.isValid).toBe(false);
455
+ expect(result.errors.some(e => e.code === 'INVALID_WIDTH')).toBe(true);
456
+ });
457
+
458
+ it('should warn for missing alt text on images', () => {
459
+ const manifest: MediaManifest = {
460
+ kind: OriginalKind.Media,
461
+ name: 'my-image',
462
+ version: '1.0.0',
463
+ resources: [createResource('image.png', 'image', 'image/png')],
464
+ metadata: {
465
+ mediaType: 'image',
466
+ mimeType: 'image/png',
467
+ }
468
+ };
469
+
470
+ const result = validator.validate(manifest);
471
+ expect(result.warnings.some(w => w.code === 'MISSING_ALT_TEXT')).toBe(true);
472
+ });
473
+ });
474
+
475
+ describe('DocumentValidator', () => {
476
+ const validator = new DocumentValidator();
477
+
478
+ it('should validate a minimal valid document manifest', () => {
479
+ const manifest: DocumentManifest = {
480
+ kind: OriginalKind.Document,
481
+ name: 'my-doc',
482
+ version: '1.0.0',
483
+ resources: [createResource('readme.md', 'document', 'text/markdown')],
484
+ metadata: {
485
+ format: 'markdown',
486
+ content: 'readme.md',
487
+ }
488
+ };
489
+
490
+ const result = validator.validate(manifest);
491
+ expect(result.isValid).toBe(true);
492
+ });
493
+
494
+ it('should fail for invalid format', () => {
495
+ const manifest: DocumentManifest = {
496
+ kind: OriginalKind.Document,
497
+ name: 'my-doc',
498
+ version: '1.0.0',
499
+ resources: [createResource('doc.xyz', 'document', 'text/plain')],
500
+ metadata: {
501
+ format: 'invalid' as any,
502
+ content: 'doc.xyz',
503
+ }
504
+ };
505
+
506
+ const result = validator.validate(manifest);
507
+ expect(result.isValid).toBe(false);
508
+ expect(result.errors.some(e => e.code === 'INVALID_FORMAT')).toBe(true);
509
+ });
510
+
511
+ it('should validate TOC structure', () => {
512
+ const manifest: DocumentManifest = {
513
+ kind: OriginalKind.Document,
514
+ name: 'my-doc',
515
+ version: '1.0.0',
516
+ resources: [createResource('doc.md', 'document', 'text/markdown')],
517
+ metadata: {
518
+ format: 'markdown',
519
+ content: 'doc.md',
520
+ toc: [
521
+ { title: 'Intro', level: 1 },
522
+ { title: '', level: 0 }, // invalid
523
+ ]
524
+ }
525
+ };
526
+
527
+ const result = validator.validate(manifest);
528
+ expect(result.isValid).toBe(false);
529
+ expect(result.errors.some(e => e.code === 'MISSING_TOC_TITLE')).toBe(true);
530
+ expect(result.errors.some(e => e.code === 'INVALID_TOC_LEVEL')).toBe(true);
531
+ });
532
+
533
+ it('should validate references uniqueness', () => {
534
+ const manifest: DocumentManifest = {
535
+ kind: OriginalKind.Document,
536
+ name: 'my-doc',
537
+ version: '1.0.0',
538
+ resources: [createResource('paper.pdf', 'document', 'application/pdf')],
539
+ metadata: {
540
+ format: 'pdf',
541
+ content: 'paper.pdf',
542
+ references: [
543
+ { id: 'ref1', title: 'Reference 1' },
544
+ { id: 'ref1', title: 'Duplicate ref' }, // duplicate
545
+ ]
546
+ }
547
+ };
548
+
549
+ const result = validator.validate(manifest);
550
+ expect(result.isValid).toBe(false);
551
+ expect(result.errors.some(e => e.code === 'DUPLICATE_REFERENCE_ID')).toBe(true);
552
+ });
553
+
554
+ it('should validate document status', () => {
555
+ const manifest: DocumentManifest = {
556
+ kind: OriginalKind.Document,
557
+ name: 'my-doc',
558
+ version: '1.0.0',
559
+ resources: [createResource('doc.md', 'document', 'text/markdown')],
560
+ metadata: {
561
+ format: 'markdown',
562
+ content: 'doc.md',
563
+ status: 'invalid' as any,
564
+ }
565
+ };
566
+
567
+ const result = validator.validate(manifest);
568
+ expect(result.isValid).toBe(false);
569
+ expect(result.errors.some(e => e.code === 'INVALID_STATUS')).toBe(true);
570
+ });
571
+ });
572
+
573
+ describe('Base validation', () => {
574
+ const validator = new AppValidator(); // Using App as representative
575
+
576
+ it('should fail when name is missing', () => {
577
+ const manifest = {
578
+ kind: OriginalKind.App,
579
+ version: '1.0.0',
580
+ resources: [createResource('index.js')],
581
+ metadata: { runtime: 'node', entrypoint: 'index.js' }
582
+ } as any;
583
+
584
+ const result = validator.validate(manifest);
585
+ expect(result.isValid).toBe(false);
586
+ expect(result.errors.some(e => e.code === 'MISSING_NAME')).toBe(true);
587
+ });
588
+
589
+ it('should fail for invalid version', () => {
590
+ const manifest = {
591
+ kind: OriginalKind.App,
592
+ name: 'my-app',
593
+ version: 'not-semver',
594
+ resources: [createResource('index.js')],
595
+ metadata: { runtime: 'node', entrypoint: 'index.js' }
596
+ } as AppManifest;
597
+
598
+ const result = validator.validate(manifest);
599
+ expect(result.isValid).toBe(false);
600
+ expect(result.errors.some(e => e.code === 'INVALID_VERSION')).toBe(true);
601
+ });
602
+
603
+ it('should fail when resources is empty', () => {
604
+ const manifest: AppManifest = {
605
+ kind: OriginalKind.App,
606
+ name: 'my-app',
607
+ version: '1.0.0',
608
+ resources: [],
609
+ metadata: { runtime: 'node', entrypoint: 'index.js' }
610
+ };
611
+
612
+ const result = validator.validate(manifest);
613
+ expect(result.isValid).toBe(false);
614
+ expect(result.errors.some(e => e.code === 'EMPTY_RESOURCES')).toBe(true);
615
+ });
616
+
617
+ it('should fail for duplicate resource IDs', () => {
618
+ const manifest: AppManifest = {
619
+ kind: OriginalKind.App,
620
+ name: 'my-app',
621
+ version: '1.0.0',
622
+ resources: [
623
+ createResource('index.js'),
624
+ createResource('index.js'), // duplicate
625
+ ],
626
+ metadata: { runtime: 'node', entrypoint: 'index.js' }
627
+ };
628
+
629
+ const result = validator.validate(manifest);
630
+ expect(result.isValid).toBe(false);
631
+ expect(result.errors.some(e => e.code === 'DUPLICATE_RESOURCE_IDS')).toBe(true);
632
+ });
633
+
634
+ it('should validate dependency DIDs', () => {
635
+ const manifest: AppManifest = {
636
+ kind: OriginalKind.App,
637
+ name: 'my-app',
638
+ version: '1.0.0',
639
+ resources: [createResource('index.js')],
640
+ dependencies: [
641
+ { did: 'not-a-did' },
642
+ ],
643
+ metadata: { runtime: 'node', entrypoint: 'index.js' }
644
+ };
645
+
646
+ const result = validator.validate(manifest);
647
+ expect(result.isValid).toBe(false);
648
+ expect(result.errors.some(e => e.code === 'INVALID_DEPENDENCY_DID')).toBe(true);
649
+ });
650
+ });
651
+