@originals/sdk 1.4.3 → 1.5.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 (222) hide show
  1. package/dist/adapters/FeeOracleMock.d.ts +6 -0
  2. package/dist/adapters/FeeOracleMock.js +8 -0
  3. package/dist/adapters/index.d.ts +4 -0
  4. package/dist/adapters/index.js +4 -0
  5. package/dist/adapters/providers/OrdHttpProvider.d.ts +56 -0
  6. package/dist/adapters/providers/OrdHttpProvider.js +110 -0
  7. package/dist/adapters/providers/OrdMockProvider.d.ts +70 -0
  8. package/dist/adapters/providers/OrdMockProvider.js +75 -0
  9. package/dist/adapters/types.d.ts +71 -0
  10. package/dist/adapters/types.js +1 -0
  11. package/dist/bitcoin/BitcoinManager.d.ts +15 -0
  12. package/dist/bitcoin/BitcoinManager.js +262 -0
  13. package/dist/bitcoin/BroadcastClient.d.ts +30 -0
  14. package/dist/bitcoin/BroadcastClient.js +35 -0
  15. package/dist/bitcoin/OrdinalsClient.d.ts +21 -0
  16. package/dist/bitcoin/OrdinalsClient.js +105 -0
  17. package/dist/bitcoin/PSBTBuilder.d.ts +24 -0
  18. package/dist/bitcoin/PSBTBuilder.js +80 -0
  19. package/dist/bitcoin/fee-calculation.d.ts +14 -0
  20. package/dist/bitcoin/fee-calculation.js +31 -0
  21. package/dist/bitcoin/providers/OrdNodeProvider.d.ts +38 -0
  22. package/dist/bitcoin/providers/OrdNodeProvider.js +67 -0
  23. package/dist/bitcoin/providers/OrdinalsProvider.d.ts +33 -0
  24. package/dist/bitcoin/providers/OrdinalsProvider.js +50 -0
  25. package/dist/bitcoin/providers/types.d.ts +63 -0
  26. package/dist/bitcoin/providers/types.js +1 -0
  27. package/dist/bitcoin/transactions/commit.d.ts +89 -0
  28. package/dist/bitcoin/transactions/commit.js +311 -0
  29. package/dist/bitcoin/transactions/index.d.ts +7 -0
  30. package/dist/bitcoin/transactions/index.js +8 -0
  31. package/dist/bitcoin/transfer.d.ts +9 -0
  32. package/dist/bitcoin/transfer.js +26 -0
  33. package/dist/bitcoin/utxo-selection.d.ts +78 -0
  34. package/dist/bitcoin/utxo-selection.js +237 -0
  35. package/dist/bitcoin/utxo.d.ts +26 -0
  36. package/dist/bitcoin/utxo.js +78 -0
  37. package/dist/contexts/credentials-v1.json +195 -0
  38. package/dist/contexts/credentials-v2-examples.json +5 -0
  39. package/dist/contexts/credentials-v2.json +301 -0
  40. package/dist/contexts/credentials.json +195 -0
  41. package/dist/contexts/data-integrity-v2.json +81 -0
  42. package/dist/contexts/dids.json +57 -0
  43. package/dist/contexts/ed255192020.json +93 -0
  44. package/dist/contexts/ordinals-plus.json +23 -0
  45. package/dist/contexts/originals.json +22 -0
  46. package/dist/core/OriginalsSDK.d.ts +158 -0
  47. package/dist/core/OriginalsSDK.js +274 -0
  48. package/dist/crypto/Multikey.d.ts +30 -0
  49. package/dist/crypto/Multikey.js +149 -0
  50. package/dist/crypto/Signer.d.ts +21 -0
  51. package/dist/crypto/Signer.js +196 -0
  52. package/dist/crypto/noble-init.d.ts +18 -0
  53. package/dist/crypto/noble-init.js +106 -0
  54. package/dist/did/BtcoDidResolver.d.ts +57 -0
  55. package/dist/did/BtcoDidResolver.js +166 -0
  56. package/dist/did/DIDManager.d.ts +101 -0
  57. package/dist/did/DIDManager.js +493 -0
  58. package/dist/did/Ed25519Verifier.d.ts +30 -0
  59. package/dist/did/Ed25519Verifier.js +59 -0
  60. package/dist/did/KeyManager.d.ts +17 -0
  61. package/dist/did/KeyManager.js +207 -0
  62. package/dist/did/WebVHManager.d.ts +100 -0
  63. package/dist/did/WebVHManager.js +312 -0
  64. package/dist/did/createBtcoDidDocument.d.ts +10 -0
  65. package/dist/did/createBtcoDidDocument.js +42 -0
  66. package/dist/did/providers/OrdinalsClientProviderAdapter.d.ts +23 -0
  67. package/dist/did/providers/OrdinalsClientProviderAdapter.js +51 -0
  68. package/dist/events/EventEmitter.d.ts +115 -0
  69. package/dist/events/EventEmitter.js +198 -0
  70. package/dist/events/index.d.ts +7 -0
  71. package/dist/events/index.js +6 -0
  72. package/dist/events/types.d.ts +286 -0
  73. package/dist/events/types.js +9 -0
  74. package/dist/examples/basic-usage.d.ts +3 -0
  75. package/dist/examples/basic-usage.js +62 -0
  76. package/dist/examples/create-module-original.d.ts +32 -0
  77. package/dist/examples/create-module-original.js +376 -0
  78. package/dist/examples/full-lifecycle-flow.d.ts +56 -0
  79. package/dist/examples/full-lifecycle-flow.js +419 -0
  80. package/dist/examples/run.d.ts +12 -0
  81. package/dist/examples/run.js +51 -0
  82. package/dist/index.d.ts +43 -0
  83. package/dist/index.js +52 -0
  84. package/dist/kinds/KindRegistry.d.ts +76 -0
  85. package/dist/kinds/KindRegistry.js +216 -0
  86. package/dist/kinds/index.d.ts +33 -0
  87. package/dist/kinds/index.js +36 -0
  88. package/dist/kinds/types.d.ts +363 -0
  89. package/dist/kinds/types.js +25 -0
  90. package/dist/kinds/validators/AgentValidator.d.ts +14 -0
  91. package/dist/kinds/validators/AgentValidator.js +155 -0
  92. package/dist/kinds/validators/AppValidator.d.ts +14 -0
  93. package/dist/kinds/validators/AppValidator.js +135 -0
  94. package/dist/kinds/validators/DatasetValidator.d.ts +14 -0
  95. package/dist/kinds/validators/DatasetValidator.js +148 -0
  96. package/dist/kinds/validators/DocumentValidator.d.ts +14 -0
  97. package/dist/kinds/validators/DocumentValidator.js +180 -0
  98. package/dist/kinds/validators/MediaValidator.d.ts +14 -0
  99. package/dist/kinds/validators/MediaValidator.js +172 -0
  100. package/dist/kinds/validators/ModuleValidator.d.ts +14 -0
  101. package/dist/kinds/validators/ModuleValidator.js +140 -0
  102. package/dist/kinds/validators/base.d.ts +96 -0
  103. package/dist/kinds/validators/base.js +218 -0
  104. package/dist/kinds/validators/index.d.ts +10 -0
  105. package/dist/kinds/validators/index.js +10 -0
  106. package/dist/lifecycle/BatchOperations.d.ts +147 -0
  107. package/dist/lifecycle/BatchOperations.js +251 -0
  108. package/dist/lifecycle/LifecycleManager.d.ts +362 -0
  109. package/dist/lifecycle/LifecycleManager.js +1692 -0
  110. package/dist/lifecycle/OriginalsAsset.d.ts +164 -0
  111. package/dist/lifecycle/OriginalsAsset.js +380 -0
  112. package/dist/lifecycle/ProvenanceQuery.d.ts +126 -0
  113. package/dist/lifecycle/ProvenanceQuery.js +220 -0
  114. package/dist/lifecycle/ResourceVersioning.d.ts +73 -0
  115. package/dist/lifecycle/ResourceVersioning.js +127 -0
  116. package/dist/migration/MigrationManager.d.ts +86 -0
  117. package/dist/migration/MigrationManager.js +412 -0
  118. package/dist/migration/audit/AuditLogger.d.ts +51 -0
  119. package/dist/migration/audit/AuditLogger.js +156 -0
  120. package/dist/migration/checkpoint/CheckpointManager.d.ts +31 -0
  121. package/dist/migration/checkpoint/CheckpointManager.js +96 -0
  122. package/dist/migration/checkpoint/CheckpointStorage.d.ts +26 -0
  123. package/dist/migration/checkpoint/CheckpointStorage.js +89 -0
  124. package/dist/migration/index.d.ts +22 -0
  125. package/dist/migration/index.js +27 -0
  126. package/dist/migration/operations/BaseMigration.d.ts +48 -0
  127. package/dist/migration/operations/BaseMigration.js +83 -0
  128. package/dist/migration/operations/PeerToBtcoMigration.d.ts +25 -0
  129. package/dist/migration/operations/PeerToBtcoMigration.js +67 -0
  130. package/dist/migration/operations/PeerToWebvhMigration.d.ts +19 -0
  131. package/dist/migration/operations/PeerToWebvhMigration.js +46 -0
  132. package/dist/migration/operations/WebvhToBtcoMigration.d.ts +25 -0
  133. package/dist/migration/operations/WebvhToBtcoMigration.js +67 -0
  134. package/dist/migration/rollback/RollbackManager.d.ts +29 -0
  135. package/dist/migration/rollback/RollbackManager.js +146 -0
  136. package/dist/migration/state/StateMachine.d.ts +25 -0
  137. package/dist/migration/state/StateMachine.js +76 -0
  138. package/dist/migration/state/StateTracker.d.ts +36 -0
  139. package/dist/migration/state/StateTracker.js +123 -0
  140. package/dist/migration/types.d.ts +306 -0
  141. package/dist/migration/types.js +33 -0
  142. package/dist/migration/validation/BitcoinValidator.d.ts +13 -0
  143. package/dist/migration/validation/BitcoinValidator.js +83 -0
  144. package/dist/migration/validation/CredentialValidator.d.ts +13 -0
  145. package/dist/migration/validation/CredentialValidator.js +46 -0
  146. package/dist/migration/validation/DIDCompatibilityValidator.d.ts +16 -0
  147. package/dist/migration/validation/DIDCompatibilityValidator.js +127 -0
  148. package/dist/migration/validation/LifecycleValidator.d.ts +10 -0
  149. package/dist/migration/validation/LifecycleValidator.js +52 -0
  150. package/dist/migration/validation/StorageValidator.d.ts +10 -0
  151. package/dist/migration/validation/StorageValidator.js +65 -0
  152. package/dist/migration/validation/ValidationPipeline.d.ts +29 -0
  153. package/dist/migration/validation/ValidationPipeline.js +180 -0
  154. package/dist/resources/ResourceManager.d.ts +231 -0
  155. package/dist/resources/ResourceManager.js +573 -0
  156. package/dist/resources/index.d.ts +11 -0
  157. package/dist/resources/index.js +10 -0
  158. package/dist/resources/types.d.ts +93 -0
  159. package/dist/resources/types.js +80 -0
  160. package/dist/storage/LocalStorageAdapter.d.ts +11 -0
  161. package/dist/storage/LocalStorageAdapter.js +53 -0
  162. package/dist/storage/MemoryStorageAdapter.d.ts +6 -0
  163. package/dist/storage/MemoryStorageAdapter.js +21 -0
  164. package/dist/storage/StorageAdapter.d.ts +16 -0
  165. package/dist/storage/StorageAdapter.js +1 -0
  166. package/dist/storage/index.d.ts +2 -0
  167. package/dist/storage/index.js +2 -0
  168. package/dist/types/bitcoin.d.ts +84 -0
  169. package/dist/types/bitcoin.js +1 -0
  170. package/dist/types/common.d.ts +82 -0
  171. package/dist/types/common.js +1 -0
  172. package/dist/types/credentials.d.ts +75 -0
  173. package/dist/types/credentials.js +1 -0
  174. package/dist/types/did.d.ts +26 -0
  175. package/dist/types/did.js +1 -0
  176. package/dist/types/index.d.ts +5 -0
  177. package/dist/types/index.js +5 -0
  178. package/dist/types/network.d.ts +78 -0
  179. package/dist/types/network.js +145 -0
  180. package/dist/utils/EventLogger.d.ts +71 -0
  181. package/dist/utils/EventLogger.js +232 -0
  182. package/dist/utils/Logger.d.ts +106 -0
  183. package/dist/utils/Logger.js +257 -0
  184. package/dist/utils/MetricsCollector.d.ts +110 -0
  185. package/dist/utils/MetricsCollector.js +264 -0
  186. package/dist/utils/bitcoin-address.d.ts +38 -0
  187. package/dist/utils/bitcoin-address.js +113 -0
  188. package/dist/utils/cbor.d.ts +2 -0
  189. package/dist/utils/cbor.js +9 -0
  190. package/dist/utils/encoding.d.ts +37 -0
  191. package/dist/utils/encoding.js +120 -0
  192. package/dist/utils/hash.d.ts +1 -0
  193. package/dist/utils/hash.js +5 -0
  194. package/dist/utils/retry.d.ts +10 -0
  195. package/dist/utils/retry.js +35 -0
  196. package/dist/utils/satoshi-validation.d.ts +60 -0
  197. package/dist/utils/satoshi-validation.js +156 -0
  198. package/dist/utils/serialization.d.ts +14 -0
  199. package/dist/utils/serialization.js +76 -0
  200. package/dist/utils/telemetry.d.ts +17 -0
  201. package/dist/utils/telemetry.js +24 -0
  202. package/dist/utils/validation.d.ts +5 -0
  203. package/dist/utils/validation.js +98 -0
  204. package/dist/vc/CredentialManager.d.ts +329 -0
  205. package/dist/vc/CredentialManager.js +615 -0
  206. package/dist/vc/Issuer.d.ts +27 -0
  207. package/dist/vc/Issuer.js +70 -0
  208. package/dist/vc/Verifier.d.ts +16 -0
  209. package/dist/vc/Verifier.js +50 -0
  210. package/dist/vc/cryptosuites/bbs.d.ts +44 -0
  211. package/dist/vc/cryptosuites/bbs.js +213 -0
  212. package/dist/vc/cryptosuites/bbsSimple.d.ts +9 -0
  213. package/dist/vc/cryptosuites/bbsSimple.js +12 -0
  214. package/dist/vc/cryptosuites/eddsa.d.ts +30 -0
  215. package/dist/vc/cryptosuites/eddsa.js +81 -0
  216. package/dist/vc/documentLoader.d.ts +16 -0
  217. package/dist/vc/documentLoader.js +59 -0
  218. package/dist/vc/proofs/data-integrity.d.ts +21 -0
  219. package/dist/vc/proofs/data-integrity.js +15 -0
  220. package/dist/vc/utils/jsonld.d.ts +2 -0
  221. package/dist/vc/utils/jsonld.js +15 -0
  222. package/package.json +2 -1
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Media Kind Validator
3
+ *
4
+ * Validates manifests for media content (image, audio, video) with format metadata.
5
+ */
6
+ import { OriginalKind, type OriginalManifest, type ValidationResult } from '../types';
7
+ import { BaseKindValidator } from './base';
8
+ /**
9
+ * Validator for Media Originals
10
+ */
11
+ export declare class MediaValidator extends BaseKindValidator<OriginalKind.Media> {
12
+ readonly kind = OriginalKind.Media;
13
+ protected validateKind(manifest: OriginalManifest<OriginalKind.Media>): ValidationResult;
14
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Media Kind Validator
3
+ *
4
+ * Validates manifests for media content (image, audio, video) with format metadata.
5
+ */
6
+ import { OriginalKind } from '../types';
7
+ import { BaseKindValidator, ValidationUtils } from './base';
8
+ /**
9
+ * Valid media types
10
+ */
11
+ const VALID_MEDIA_TYPES = ['image', 'audio', 'video', '3d', 'animation'];
12
+ /**
13
+ * Common MIME types by media type
14
+ */
15
+ const COMMON_MIME_TYPES = {
16
+ image: [
17
+ 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml',
18
+ 'image/avif', 'image/bmp', 'image/tiff', 'image/heic', 'image/heif',
19
+ ],
20
+ audio: [
21
+ 'audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/ogg', 'audio/flac',
22
+ 'audio/aac', 'audio/webm', 'audio/midi', 'audio/x-wav',
23
+ ],
24
+ video: [
25
+ 'video/mp4', 'video/webm', 'video/ogg', 'video/quicktime', 'video/x-msvideo',
26
+ 'video/x-matroska', 'video/mpeg',
27
+ ],
28
+ '3d': [
29
+ 'model/gltf+json', 'model/gltf-binary', 'model/obj', 'model/stl',
30
+ 'application/octet-stream',
31
+ ],
32
+ animation: [
33
+ 'image/gif', 'video/mp4', 'video/webm', 'application/json', // Lottie
34
+ ],
35
+ };
36
+ /**
37
+ * Validator for Media Originals
38
+ */
39
+ export class MediaValidator extends BaseKindValidator {
40
+ constructor() {
41
+ super(...arguments);
42
+ this.kind = OriginalKind.Media;
43
+ }
44
+ validateKind(manifest) {
45
+ const errors = [];
46
+ const warnings = [];
47
+ const metadata = manifest.metadata;
48
+ // Validate metadata exists
49
+ if (!metadata || typeof metadata !== 'object') {
50
+ return ValidationUtils.failure([
51
+ ValidationUtils.error('MISSING_METADATA', 'Media manifest must have metadata', 'metadata'),
52
+ ]);
53
+ }
54
+ // Validate mediaType (required)
55
+ if (!metadata.mediaType) {
56
+ errors.push(ValidationUtils.error('MISSING_MEDIA_TYPE', 'Media must specify a mediaType', 'metadata.mediaType'));
57
+ }
58
+ else if (!VALID_MEDIA_TYPES.includes(metadata.mediaType)) {
59
+ errors.push(ValidationUtils.error('INVALID_MEDIA_TYPE', `Invalid mediaType: "${metadata.mediaType}". Must be one of: ${VALID_MEDIA_TYPES.join(', ')}`, 'metadata.mediaType', metadata.mediaType));
60
+ }
61
+ // Validate mimeType (required)
62
+ if (!metadata.mimeType || typeof metadata.mimeType !== 'string') {
63
+ errors.push(ValidationUtils.error('MISSING_MIME_TYPE', 'Media must specify a mimeType', 'metadata.mimeType'));
64
+ }
65
+ else if (!ValidationUtils.isValidMimeType(metadata.mimeType)) {
66
+ errors.push(ValidationUtils.error('INVALID_MIME_TYPE', `Invalid mimeType format: "${metadata.mimeType}"`, 'metadata.mimeType', metadata.mimeType));
67
+ }
68
+ else if (metadata.mediaType) {
69
+ // Check if MIME type matches the declared media type
70
+ const expectedMimeTypes = COMMON_MIME_TYPES[metadata.mediaType];
71
+ if (expectedMimeTypes && !expectedMimeTypes.includes(metadata.mimeType)) {
72
+ warnings.push(ValidationUtils.warning('MIME_TYPE_MISMATCH', `mimeType "${metadata.mimeType}" is not typically associated with mediaType "${metadata.mediaType}"`, 'metadata.mimeType'));
73
+ }
74
+ }
75
+ // Validate dimensions for images and video
76
+ if (metadata.mediaType === 'image' || metadata.mediaType === 'video') {
77
+ if (metadata.dimensions) {
78
+ if (typeof metadata.dimensions !== 'object') {
79
+ errors.push(ValidationUtils.error('INVALID_DIMENSIONS', 'Dimensions must be an object', 'metadata.dimensions'));
80
+ }
81
+ else {
82
+ if (typeof metadata.dimensions.width !== 'number' || metadata.dimensions.width <= 0) {
83
+ errors.push(ValidationUtils.error('INVALID_WIDTH', 'Width must be a positive number', 'metadata.dimensions.width'));
84
+ }
85
+ if (typeof metadata.dimensions.height !== 'number' || metadata.dimensions.height <= 0) {
86
+ errors.push(ValidationUtils.error('INVALID_HEIGHT', 'Height must be a positive number', 'metadata.dimensions.height'));
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ warnings.push(ValidationUtils.warning('MISSING_DIMENSIONS', `Consider specifying dimensions for ${metadata.mediaType} content`, 'metadata.dimensions'));
92
+ }
93
+ }
94
+ // Validate duration for audio and video
95
+ if (metadata.mediaType === 'audio' || metadata.mediaType === 'video') {
96
+ if (metadata.duration !== undefined) {
97
+ if (typeof metadata.duration !== 'number' || metadata.duration < 0) {
98
+ errors.push(ValidationUtils.error('INVALID_DURATION', 'Duration must be a non-negative number (seconds)', 'metadata.duration'));
99
+ }
100
+ }
101
+ else {
102
+ warnings.push(ValidationUtils.warning('MISSING_DURATION', `Consider specifying duration for ${metadata.mediaType} content`, 'metadata.duration'));
103
+ }
104
+ }
105
+ // Validate frameRate for video
106
+ if (metadata.mediaType === 'video' || metadata.mediaType === 'animation') {
107
+ if (metadata.frameRate !== undefined) {
108
+ if (typeof metadata.frameRate !== 'number' || metadata.frameRate <= 0) {
109
+ errors.push(ValidationUtils.error('INVALID_FRAME_RATE', 'Frame rate must be a positive number', 'metadata.frameRate'));
110
+ }
111
+ }
112
+ }
113
+ // Validate audio-specific fields
114
+ if (metadata.mediaType === 'audio' || metadata.mediaType === 'video') {
115
+ if (metadata.audioChannels !== undefined) {
116
+ if (typeof metadata.audioChannels !== 'number' ||
117
+ metadata.audioChannels <= 0 ||
118
+ !Number.isInteger(metadata.audioChannels)) {
119
+ errors.push(ValidationUtils.error('INVALID_AUDIO_CHANNELS', 'Audio channels must be a positive integer', 'metadata.audioChannels'));
120
+ }
121
+ }
122
+ if (metadata.sampleRate !== undefined) {
123
+ if (typeof metadata.sampleRate !== 'number' || metadata.sampleRate <= 0) {
124
+ errors.push(ValidationUtils.error('INVALID_SAMPLE_RATE', 'Sample rate must be a positive number', 'metadata.sampleRate'));
125
+ }
126
+ }
127
+ }
128
+ // Validate bitrate if specified
129
+ if (metadata.bitrate !== undefined) {
130
+ if (typeof metadata.bitrate !== 'number' || metadata.bitrate <= 0) {
131
+ errors.push(ValidationUtils.error('INVALID_BITRATE', 'Bitrate must be a positive number (kbps)', 'metadata.bitrate'));
132
+ }
133
+ }
134
+ // Validate thumbnail if specified
135
+ if (metadata.thumbnail) {
136
+ if (typeof metadata.thumbnail !== 'string') {
137
+ errors.push(ValidationUtils.error('INVALID_THUMBNAIL', 'Thumbnail must be a string (resource ID)', 'metadata.thumbnail'));
138
+ }
139
+ else if (!ValidationUtils.resourceExists(metadata.thumbnail, manifest.resources)) {
140
+ warnings.push(ValidationUtils.warning('THUMBNAIL_NOT_RESOURCE', `Thumbnail "${metadata.thumbnail}" does not match a resource ID`, 'metadata.thumbnail'));
141
+ }
142
+ }
143
+ // Validate preview if specified
144
+ if (metadata.preview) {
145
+ if (typeof metadata.preview !== 'string') {
146
+ errors.push(ValidationUtils.error('INVALID_PREVIEW', 'Preview must be a string (resource ID)', 'metadata.preview'));
147
+ }
148
+ else if (!ValidationUtils.resourceExists(metadata.preview, manifest.resources)) {
149
+ warnings.push(ValidationUtils.warning('PREVIEW_NOT_RESOURCE', `Preview "${metadata.preview}" does not match a resource ID`, 'metadata.preview'));
150
+ }
151
+ }
152
+ // Suggest adding alt text for accessibility
153
+ if (!metadata.altText && metadata.mediaType === 'image') {
154
+ warnings.push(ValidationUtils.warning('MISSING_ALT_TEXT', 'Consider adding altText for accessibility', 'metadata.altText'));
155
+ }
156
+ // Check that at least one media resource exists
157
+ const mediaResources = manifest.resources.filter(r => r.type === 'media' ||
158
+ r.type === 'image' ||
159
+ r.type === 'audio' ||
160
+ r.type === 'video' ||
161
+ r.contentType.startsWith('image/') ||
162
+ r.contentType.startsWith('audio/') ||
163
+ r.contentType.startsWith('video/') ||
164
+ r.contentType.startsWith('model/'));
165
+ if (mediaResources.length === 0) {
166
+ warnings.push(ValidationUtils.warning('NO_MEDIA_RESOURCES', 'No media resources found. Ensure resources have appropriate types', 'resources'));
167
+ }
168
+ return errors.length > 0
169
+ ? ValidationUtils.failure(errors, warnings)
170
+ : ValidationUtils.success(warnings);
171
+ }
172
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Module Kind Validator
3
+ *
4
+ * Validates manifests for reusable code modules with exports and dependencies.
5
+ */
6
+ import { OriginalKind, type OriginalManifest, type ValidationResult } from '../types';
7
+ import { BaseKindValidator } from './base';
8
+ /**
9
+ * Validator for Module Originals
10
+ */
11
+ export declare class ModuleValidator extends BaseKindValidator<OriginalKind.Module> {
12
+ readonly kind = OriginalKind.Module;
13
+ protected validateKind(manifest: OriginalManifest<OriginalKind.Module>): ValidationResult;
14
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Module Kind Validator
3
+ *
4
+ * Validates manifests for reusable code modules with exports and dependencies.
5
+ */
6
+ import { OriginalKind } from '../types';
7
+ import { BaseKindValidator, ValidationUtils } from './base';
8
+ /**
9
+ * Valid module formats
10
+ */
11
+ const VALID_FORMATS = ['esm', 'commonjs', 'umd', 'amd', 'iife'];
12
+ /**
13
+ * Validator for Module Originals
14
+ */
15
+ export class ModuleValidator extends BaseKindValidator {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.kind = OriginalKind.Module;
19
+ }
20
+ validateKind(manifest) {
21
+ const errors = [];
22
+ const warnings = [];
23
+ const metadata = manifest.metadata;
24
+ // Validate metadata exists
25
+ if (!metadata || typeof metadata !== 'object') {
26
+ return ValidationUtils.failure([
27
+ ValidationUtils.error('MISSING_METADATA', 'Module manifest must have metadata', 'metadata'),
28
+ ]);
29
+ }
30
+ // Validate format (required)
31
+ if (!metadata.format) {
32
+ errors.push(ValidationUtils.error('MISSING_FORMAT', 'Module must specify a format', 'metadata.format'));
33
+ }
34
+ else if (!VALID_FORMATS.includes(metadata.format)) {
35
+ errors.push(ValidationUtils.error('INVALID_FORMAT', `Invalid module format: "${metadata.format}". Must be one of: ${VALID_FORMATS.join(', ')}`, 'metadata.format', metadata.format));
36
+ }
37
+ // Validate main (required)
38
+ if (!metadata.main || typeof metadata.main !== 'string') {
39
+ errors.push(ValidationUtils.error('MISSING_MAIN', 'Module must specify a main entrypoint', 'metadata.main'));
40
+ }
41
+ else {
42
+ // Check if main references an existing resource
43
+ if (!ValidationUtils.resourceExists(metadata.main, manifest.resources)) {
44
+ warnings.push(ValidationUtils.warning('MAIN_NOT_RESOURCE', `Main entrypoint "${metadata.main}" does not match a resource ID`, 'metadata.main', 'Ensure the main entrypoint is a valid resource ID'));
45
+ }
46
+ }
47
+ // Validate types if specified
48
+ if (metadata.types) {
49
+ if (typeof metadata.types !== 'string') {
50
+ errors.push(ValidationUtils.error('INVALID_TYPES', 'Types must be a string (resource ID)', 'metadata.types'));
51
+ }
52
+ else if (!ValidationUtils.resourceExists(metadata.types, manifest.resources)) {
53
+ warnings.push(ValidationUtils.warning('TYPES_NOT_RESOURCE', `Types file "${metadata.types}" does not match a resource ID`, 'metadata.types'));
54
+ }
55
+ }
56
+ else {
57
+ warnings.push(ValidationUtils.warning('MISSING_TYPES', 'Consider adding TypeScript type definitions', 'metadata.types', 'Add a .d.ts file for better TypeScript support'));
58
+ }
59
+ // Validate exports if specified
60
+ if (metadata.exports) {
61
+ if (typeof metadata.exports !== 'object' || Array.isArray(metadata.exports)) {
62
+ errors.push(ValidationUtils.error('INVALID_EXPORTS', 'Exports must be an object', 'metadata.exports'));
63
+ }
64
+ else {
65
+ for (const [key, value] of Object.entries(metadata.exports)) {
66
+ if (typeof value === 'string') {
67
+ // Simple string export is valid
68
+ continue;
69
+ }
70
+ else if (typeof value === 'object' && value !== null) {
71
+ // Conditional exports object
72
+ const exportObj = value;
73
+ if (!exportObj.import && !exportObj.require) {
74
+ warnings.push(ValidationUtils.warning('INCOMPLETE_EXPORT', `Export "${key}" should have at least 'import' or 'require' field`, `metadata.exports.${key}`));
75
+ }
76
+ }
77
+ else {
78
+ errors.push(ValidationUtils.error('INVALID_EXPORT', `Export "${key}" must be a string or object`, `metadata.exports.${key}`));
79
+ }
80
+ }
81
+ // Check for "." export (main export)
82
+ if (!('.' in metadata.exports)) {
83
+ warnings.push(ValidationUtils.warning('MISSING_MAIN_EXPORT', 'Consider adding a "." export for the main module entry', 'metadata.exports'));
84
+ }
85
+ }
86
+ }
87
+ // Validate peer dependencies if specified
88
+ if (metadata.peerDependencies) {
89
+ if (typeof metadata.peerDependencies !== 'object' || Array.isArray(metadata.peerDependencies)) {
90
+ errors.push(ValidationUtils.error('INVALID_PEER_DEPS', 'Peer dependencies must be an object', 'metadata.peerDependencies'));
91
+ }
92
+ else {
93
+ for (const [name, version] of Object.entries(metadata.peerDependencies)) {
94
+ if (typeof version !== 'string') {
95
+ errors.push(ValidationUtils.error('INVALID_PEER_DEP_VERSION', `Peer dependency "${name}" must have a string version`, `metadata.peerDependencies.${name}`));
96
+ }
97
+ }
98
+ }
99
+ }
100
+ // Validate browser field if specified
101
+ if (metadata.browser) {
102
+ if (typeof metadata.browser !== 'string') {
103
+ errors.push(ValidationUtils.error('INVALID_BROWSER', 'Browser field must be a string (resource ID)', 'metadata.browser'));
104
+ }
105
+ else if (!ValidationUtils.resourceExists(metadata.browser, manifest.resources)) {
106
+ warnings.push(ValidationUtils.warning('BROWSER_NOT_RESOURCE', `Browser entrypoint "${metadata.browser}" does not match a resource ID`, 'metadata.browser'));
107
+ }
108
+ }
109
+ // Validate sideEffects if specified
110
+ if (metadata.sideEffects !== undefined) {
111
+ if (typeof metadata.sideEffects !== 'boolean' && !Array.isArray(metadata.sideEffects)) {
112
+ errors.push(ValidationUtils.error('INVALID_SIDE_EFFECTS', 'sideEffects must be a boolean or array of strings', 'metadata.sideEffects'));
113
+ }
114
+ else if (Array.isArray(metadata.sideEffects)) {
115
+ for (let i = 0; i < metadata.sideEffects.length; i++) {
116
+ if (typeof metadata.sideEffects[i] !== 'string') {
117
+ errors.push(ValidationUtils.error('INVALID_SIDE_EFFECT_ENTRY', `sideEffects entry at index ${i} must be a string`, `metadata.sideEffects[${i}]`));
118
+ }
119
+ }
120
+ }
121
+ }
122
+ // Validate TypeScript config if specified
123
+ if (metadata.typescript) {
124
+ if (typeof metadata.typescript !== 'object') {
125
+ errors.push(ValidationUtils.error('INVALID_TYPESCRIPT', 'TypeScript config must be an object', 'metadata.typescript'));
126
+ }
127
+ }
128
+ // Check that at least one code resource exists
129
+ const codeResources = manifest.resources.filter(r => r.contentType.includes('javascript') ||
130
+ r.contentType.includes('typescript') ||
131
+ r.contentType.includes('json') ||
132
+ r.type === 'code');
133
+ if (codeResources.length === 0) {
134
+ warnings.push(ValidationUtils.warning('NO_CODE_RESOURCES', 'No code resources found. Ensure resources have appropriate content types', 'resources'));
135
+ }
136
+ return errors.length > 0
137
+ ? ValidationUtils.failure(errors, warnings)
138
+ : ValidationUtils.success(warnings);
139
+ }
140
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Base validator interface and common validation utilities
3
+ */
4
+ import type { OriginalKind, OriginalManifest, ValidationResult, ValidationError, ValidationWarning, BaseManifest } from '../types';
5
+ import type { AssetResource } from '../../types/common';
6
+ /**
7
+ * Interface for kind-specific validators
8
+ */
9
+ export interface KindValidator<K extends OriginalKind = OriginalKind> {
10
+ /** The kind this validator handles */
11
+ readonly kind: K;
12
+ /**
13
+ * Validate a manifest for this kind
14
+ * @param manifest - The manifest to validate
15
+ * @returns Validation result with errors and warnings
16
+ */
17
+ validate(manifest: OriginalManifest<K>): ValidationResult;
18
+ }
19
+ /**
20
+ * Common validation utilities
21
+ */
22
+ export declare class ValidationUtils {
23
+ /**
24
+ * Check if a string is a valid semantic version
25
+ */
26
+ static isValidSemver(version: string): boolean;
27
+ /**
28
+ * Check if a string is a valid DID
29
+ */
30
+ static isValidDID(did: string): boolean;
31
+ /**
32
+ * Check if a string is a valid SPDX license identifier
33
+ */
34
+ static isValidSPDXLicense(license: string): boolean;
35
+ /**
36
+ * Check if a string is a valid MIME type
37
+ */
38
+ static isValidMimeType(mimeType: string): boolean;
39
+ /**
40
+ * Check if a string is a valid URL
41
+ */
42
+ static isValidURL(url: string): boolean;
43
+ /**
44
+ * Check if a string is a valid ISO 639-1 language code
45
+ */
46
+ static isValidLanguageCode(code: string): boolean;
47
+ /**
48
+ * Check if a resource ID exists in the resources array
49
+ */
50
+ static resourceExists(resourceId: string, resources: AssetResource[]): boolean;
51
+ /**
52
+ * Get a resource by ID
53
+ */
54
+ static getResource(resourceId: string, resources: AssetResource[]): AssetResource | undefined;
55
+ /**
56
+ * Create a validation error
57
+ */
58
+ static error(code: string, message: string, path?: string, value?: unknown): ValidationError;
59
+ /**
60
+ * Create a validation warning
61
+ */
62
+ static warning(code: string, message: string, path?: string, suggestion?: string): ValidationWarning;
63
+ /**
64
+ * Create a successful validation result
65
+ */
66
+ static success(warnings?: ValidationWarning[]): ValidationResult;
67
+ /**
68
+ * Create a failed validation result
69
+ */
70
+ static failure(errors: ValidationError[], warnings?: ValidationWarning[]): ValidationResult;
71
+ /**
72
+ * Merge multiple validation results
73
+ */
74
+ static merge(...results: ValidationResult[]): ValidationResult;
75
+ }
76
+ /**
77
+ * Base validator class with common validation logic
78
+ */
79
+ export declare abstract class BaseKindValidator<K extends OriginalKind> implements KindValidator<K> {
80
+ abstract readonly kind: K;
81
+ /**
82
+ * Validate a manifest
83
+ * Combines base validation with kind-specific validation
84
+ */
85
+ validate(manifest: OriginalManifest<K>): ValidationResult;
86
+ /**
87
+ * Validate base manifest fields common to all kinds
88
+ */
89
+ protected validateBase(manifest: BaseManifest & {
90
+ kind: K;
91
+ }): ValidationResult;
92
+ /**
93
+ * Kind-specific validation to be implemented by subclasses
94
+ */
95
+ protected abstract validateKind(manifest: OriginalManifest<K>): ValidationResult;
96
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Base validator interface and common validation utilities
3
+ */
4
+ /**
5
+ * Common validation utilities
6
+ */
7
+ export class ValidationUtils {
8
+ /**
9
+ * Check if a string is a valid semantic version
10
+ */
11
+ static isValidSemver(version) {
12
+ const semverRegex = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
13
+ return semverRegex.test(version);
14
+ }
15
+ /**
16
+ * Check if a string is a valid DID
17
+ */
18
+ static isValidDID(did) {
19
+ // DID format: did:method:identifier (identifier can contain : for path segments)
20
+ // Examples: did:peer:123, did:webvh:example.com:user, did:btco:12345
21
+ const didRegex = /^did:[a-z0-9]+:[a-zA-Z0-9._:%-]+$/;
22
+ return didRegex.test(did);
23
+ }
24
+ /**
25
+ * Check if a string is a valid SPDX license identifier
26
+ */
27
+ static isValidSPDXLicense(license) {
28
+ // Common SPDX identifiers (not exhaustive)
29
+ const commonLicenses = [
30
+ 'MIT', 'Apache-2.0', 'GPL-3.0', 'GPL-2.0', 'BSD-2-Clause', 'BSD-3-Clause',
31
+ 'ISC', 'MPL-2.0', 'LGPL-3.0', 'AGPL-3.0', 'Unlicense', 'CC0-1.0',
32
+ 'CC-BY-4.0', 'CC-BY-SA-4.0', 'CC-BY-NC-4.0', 'WTFPL', 'Zlib', 'BSL-1.0',
33
+ 'MIT-0', 'Apache-1.0', 'Apache-1.1', 'EPL-2.0', 'EUPL-1.2',
34
+ ];
35
+ return commonLicenses.includes(license) || /^[A-Z0-9][A-Z0-9._-]*$/i.test(license);
36
+ }
37
+ /**
38
+ * Check if a string is a valid MIME type
39
+ */
40
+ static isValidMimeType(mimeType) {
41
+ const mimeRegex = /^[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]{0,126}\/[a-zA-Z0-9][a-zA-Z0-9!#$&^_.+-]{0,126}$/;
42
+ return mimeRegex.test(mimeType);
43
+ }
44
+ /**
45
+ * Check if a string is a valid URL
46
+ */
47
+ static isValidURL(url) {
48
+ try {
49
+ new URL(url);
50
+ return true;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Check if a string is a valid ISO 639-1 language code
58
+ */
59
+ static isValidLanguageCode(code) {
60
+ // ISO 639-1 is 2 lowercase letters
61
+ return /^[a-z]{2}$/.test(code);
62
+ }
63
+ /**
64
+ * Check if a resource ID exists in the resources array
65
+ */
66
+ static resourceExists(resourceId, resources) {
67
+ return resources.some(r => r.id === resourceId);
68
+ }
69
+ /**
70
+ * Get a resource by ID
71
+ */
72
+ static getResource(resourceId, resources) {
73
+ return resources.find(r => r.id === resourceId);
74
+ }
75
+ /**
76
+ * Create a validation error
77
+ */
78
+ static error(code, message, path, value) {
79
+ return { code, message, path, value };
80
+ }
81
+ /**
82
+ * Create a validation warning
83
+ */
84
+ static warning(code, message, path, suggestion) {
85
+ return { code, message, path, suggestion };
86
+ }
87
+ /**
88
+ * Create a successful validation result
89
+ */
90
+ static success(warnings = []) {
91
+ return { isValid: true, errors: [], warnings };
92
+ }
93
+ /**
94
+ * Create a failed validation result
95
+ */
96
+ static failure(errors, warnings = []) {
97
+ return { isValid: false, errors, warnings };
98
+ }
99
+ /**
100
+ * Merge multiple validation results
101
+ */
102
+ static merge(...results) {
103
+ const errors = [];
104
+ const warnings = [];
105
+ for (const result of results) {
106
+ errors.push(...result.errors);
107
+ warnings.push(...result.warnings);
108
+ }
109
+ return {
110
+ isValid: errors.length === 0,
111
+ errors,
112
+ warnings,
113
+ };
114
+ }
115
+ }
116
+ /**
117
+ * Base validator class with common validation logic
118
+ */
119
+ export class BaseKindValidator {
120
+ /**
121
+ * Validate a manifest
122
+ * Combines base validation with kind-specific validation
123
+ */
124
+ validate(manifest) {
125
+ const baseResult = this.validateBase(manifest);
126
+ const kindResult = this.validateKind(manifest);
127
+ return ValidationUtils.merge(baseResult, kindResult);
128
+ }
129
+ /**
130
+ * Validate base manifest fields common to all kinds
131
+ */
132
+ validateBase(manifest) {
133
+ const errors = [];
134
+ const warnings = [];
135
+ // Validate kind
136
+ if (!manifest.kind) {
137
+ errors.push(ValidationUtils.error('MISSING_KIND', 'Manifest must specify a kind', 'kind'));
138
+ }
139
+ // Validate name
140
+ if (!manifest.name || typeof manifest.name !== 'string') {
141
+ errors.push(ValidationUtils.error('MISSING_NAME', 'Manifest must have a name', 'name'));
142
+ }
143
+ else if (manifest.name.length < 1 || manifest.name.length > 200) {
144
+ errors.push(ValidationUtils.error('INVALID_NAME_LENGTH', 'Name must be between 1 and 200 characters', 'name', manifest.name));
145
+ }
146
+ // Validate version
147
+ if (!manifest.version || typeof manifest.version !== 'string') {
148
+ errors.push(ValidationUtils.error('MISSING_VERSION', 'Manifest must have a version', 'version'));
149
+ }
150
+ else if (!ValidationUtils.isValidSemver(manifest.version)) {
151
+ errors.push(ValidationUtils.error('INVALID_VERSION', 'Version must be a valid semantic version (e.g., 1.0.0)', 'version', manifest.version));
152
+ }
153
+ // Validate resources
154
+ if (!manifest.resources || !Array.isArray(manifest.resources)) {
155
+ errors.push(ValidationUtils.error('MISSING_RESOURCES', 'Manifest must have resources array', 'resources'));
156
+ }
157
+ else if (manifest.resources.length === 0) {
158
+ errors.push(ValidationUtils.error('EMPTY_RESOURCES', 'Manifest must have at least one resource', 'resources'));
159
+ }
160
+ else {
161
+ // Validate each resource
162
+ for (let i = 0; i < manifest.resources.length; i++) {
163
+ const resource = manifest.resources[i];
164
+ const resourcePath = `resources[${i}]`;
165
+ if (!resource.id || typeof resource.id !== 'string') {
166
+ errors.push(ValidationUtils.error('INVALID_RESOURCE_ID', `Resource at index ${i} must have an id`, `${resourcePath}.id`));
167
+ }
168
+ if (!resource.type || typeof resource.type !== 'string') {
169
+ errors.push(ValidationUtils.error('INVALID_RESOURCE_TYPE', `Resource at index ${i} must have a type`, `${resourcePath}.type`));
170
+ }
171
+ if (!resource.contentType || !ValidationUtils.isValidMimeType(resource.contentType)) {
172
+ errors.push(ValidationUtils.error('INVALID_CONTENT_TYPE', `Resource at index ${i} must have a valid MIME contentType`, `${resourcePath}.contentType`, resource.contentType));
173
+ }
174
+ if (!resource.hash || typeof resource.hash !== 'string' || !/^[0-9a-fA-F]+$/.test(resource.hash)) {
175
+ errors.push(ValidationUtils.error('INVALID_RESOURCE_HASH', `Resource at index ${i} must have a valid hex hash`, `${resourcePath}.hash`));
176
+ }
177
+ }
178
+ // Check for duplicate resource IDs
179
+ const resourceIds = manifest.resources.map(r => r.id);
180
+ const duplicates = resourceIds.filter((id, index) => resourceIds.indexOf(id) !== index);
181
+ if (duplicates.length > 0) {
182
+ errors.push(ValidationUtils.error('DUPLICATE_RESOURCE_IDS', `Duplicate resource IDs found: ${[...new Set(duplicates)].join(', ')}`, 'resources'));
183
+ }
184
+ }
185
+ // Validate dependencies if present
186
+ if (manifest.dependencies) {
187
+ if (!Array.isArray(manifest.dependencies)) {
188
+ errors.push(ValidationUtils.error('INVALID_DEPENDENCIES', 'Dependencies must be an array', 'dependencies'));
189
+ }
190
+ else {
191
+ for (let i = 0; i < manifest.dependencies.length; i++) {
192
+ const dep = manifest.dependencies[i];
193
+ const depPath = `dependencies[${i}]`;
194
+ if (!dep.did || !ValidationUtils.isValidDID(dep.did)) {
195
+ errors.push(ValidationUtils.error('INVALID_DEPENDENCY_DID', `Dependency at index ${i} must have a valid DID`, `${depPath}.did`, dep.did));
196
+ }
197
+ }
198
+ }
199
+ }
200
+ // Validate optional fields
201
+ if (manifest.license && !ValidationUtils.isValidSPDXLicense(manifest.license)) {
202
+ warnings.push(ValidationUtils.warning('UNKNOWN_LICENSE', `License "${manifest.license}" is not a recognized SPDX identifier`, 'license', 'Use a valid SPDX license identifier like MIT, Apache-2.0, etc.'));
203
+ }
204
+ if (manifest.homepage && !ValidationUtils.isValidURL(manifest.homepage)) {
205
+ errors.push(ValidationUtils.error('INVALID_HOMEPAGE', 'Homepage must be a valid URL', 'homepage', manifest.homepage));
206
+ }
207
+ if (manifest.repository && !ValidationUtils.isValidURL(manifest.repository)) {
208
+ errors.push(ValidationUtils.error('INVALID_REPOSITORY', 'Repository must be a valid URL', 'repository', manifest.repository));
209
+ }
210
+ // Suggest adding description if missing
211
+ if (!manifest.description) {
212
+ warnings.push(ValidationUtils.warning('MISSING_DESCRIPTION', 'Consider adding a description for better discoverability', 'description', 'Add a brief description of this Original'));
213
+ }
214
+ return errors.length > 0
215
+ ? ValidationUtils.failure(errors, warnings)
216
+ : ValidationUtils.success(warnings);
217
+ }
218
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Kind validators exports
3
+ */
4
+ export { BaseKindValidator, ValidationUtils, type KindValidator } from './base';
5
+ export { AppValidator } from './AppValidator';
6
+ export { AgentValidator } from './AgentValidator';
7
+ export { ModuleValidator } from './ModuleValidator';
8
+ export { DatasetValidator } from './DatasetValidator';
9
+ export { MediaValidator } from './MediaValidator';
10
+ export { DocumentValidator } from './DocumentValidator';