@wemush/wols 0.1.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 (87) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +294 -0
  3. package/dist/cjs/compact-url.js +272 -0
  4. package/dist/cjs/compact-url.js.map +1 -0
  5. package/dist/cjs/crypto/decrypt.js +125 -0
  6. package/dist/cjs/crypto/decrypt.js.map +1 -0
  7. package/dist/cjs/crypto/encrypt.js +151 -0
  8. package/dist/cjs/crypto/encrypt.js.map +1 -0
  9. package/dist/cjs/crypto/index.js +16 -0
  10. package/dist/cjs/crypto/index.js.map +1 -0
  11. package/dist/cjs/errors.js +188 -0
  12. package/dist/cjs/errors.js.map +1 -0
  13. package/dist/cjs/index.js +81 -0
  14. package/dist/cjs/index.js.map +1 -0
  15. package/dist/cjs/parser.js +148 -0
  16. package/dist/cjs/parser.js.map +1 -0
  17. package/dist/cjs/qr/generate.js +275 -0
  18. package/dist/cjs/qr/generate.js.map +1 -0
  19. package/dist/cjs/qr/index.js +18 -0
  20. package/dist/cjs/qr/index.js.map +1 -0
  21. package/dist/cjs/specimen.js +163 -0
  22. package/dist/cjs/specimen.js.map +1 -0
  23. package/dist/cjs/types.js +78 -0
  24. package/dist/cjs/types.js.map +1 -0
  25. package/dist/cjs/utils/cuid.js +150 -0
  26. package/dist/cjs/utils/cuid.js.map +1 -0
  27. package/dist/cjs/utils/iso8601.js +131 -0
  28. package/dist/cjs/utils/iso8601.js.map +1 -0
  29. package/dist/cjs/validator.js +307 -0
  30. package/dist/cjs/validator.js.map +1 -0
  31. package/dist/esm/compact-url.js +264 -0
  32. package/dist/esm/compact-url.js.map +1 -0
  33. package/dist/esm/crypto/decrypt.js +122 -0
  34. package/dist/esm/crypto/decrypt.js.map +1 -0
  35. package/dist/esm/crypto/encrypt.js +147 -0
  36. package/dist/esm/crypto/encrypt.js.map +1 -0
  37. package/dist/esm/crypto/index.js +10 -0
  38. package/dist/esm/crypto/index.js.map +1 -0
  39. package/dist/esm/errors.js +178 -0
  40. package/dist/esm/errors.js.map +1 -0
  41. package/dist/esm/index.js +47 -0
  42. package/dist/esm/index.js.map +1 -0
  43. package/dist/esm/parser.js +145 -0
  44. package/dist/esm/parser.js.map +1 -0
  45. package/dist/esm/qr/generate.js +235 -0
  46. package/dist/esm/qr/generate.js.map +1 -0
  47. package/dist/esm/qr/index.js +10 -0
  48. package/dist/esm/qr/index.js.map +1 -0
  49. package/dist/esm/specimen.js +159 -0
  50. package/dist/esm/specimen.js.map +1 -0
  51. package/dist/esm/types.js +71 -0
  52. package/dist/esm/types.js.map +1 -0
  53. package/dist/esm/utils/cuid.js +145 -0
  54. package/dist/esm/utils/cuid.js.map +1 -0
  55. package/dist/esm/utils/iso8601.js +122 -0
  56. package/dist/esm/utils/iso8601.js.map +1 -0
  57. package/dist/esm/validator.js +304 -0
  58. package/dist/esm/validator.js.map +1 -0
  59. package/dist/types/compact-url.d.ts +104 -0
  60. package/dist/types/compact-url.d.ts.map +1 -0
  61. package/dist/types/crypto/decrypt.d.ts +33 -0
  62. package/dist/types/crypto/decrypt.d.ts.map +1 -0
  63. package/dist/types/crypto/encrypt.d.ts +32 -0
  64. package/dist/types/crypto/encrypt.d.ts.map +1 -0
  65. package/dist/types/crypto/index.d.ts +10 -0
  66. package/dist/types/crypto/index.d.ts.map +1 -0
  67. package/dist/types/errors.d.ts +103 -0
  68. package/dist/types/errors.d.ts.map +1 -0
  69. package/dist/types/index.d.ts +21 -0
  70. package/dist/types/index.d.ts.map +1 -0
  71. package/dist/types/parser.d.ts +30 -0
  72. package/dist/types/parser.d.ts.map +1 -0
  73. package/dist/types/qr/generate.d.ts +62 -0
  74. package/dist/types/qr/generate.d.ts.map +1 -0
  75. package/dist/types/qr/index.d.ts +10 -0
  76. package/dist/types/qr/index.d.ts.map +1 -0
  77. package/dist/types/specimen.d.ts +71 -0
  78. package/dist/types/specimen.d.ts.map +1 -0
  79. package/dist/types/types.d.ts +269 -0
  80. package/dist/types/types.d.ts.map +1 -0
  81. package/dist/types/utils/cuid.d.ts +44 -0
  82. package/dist/types/utils/cuid.d.ts.map +1 -0
  83. package/dist/types/utils/iso8601.d.ts +79 -0
  84. package/dist/types/utils/iso8601.d.ts.map +1 -0
  85. package/dist/types/validator.d.ts +25 -0
  86. package/dist/types/validator.d.ts.map +1 -0
  87. package/package.json +95 -0
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ /**
3
+ * QR Code Generation Module
4
+ *
5
+ * This module provides QR code generation functionality for WOLS specimens.
6
+ * Requires the 'qrcode' package as an optional peer dependency.
7
+ *
8
+ * @module qr/generate
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.isQRAvailable = isQRAvailable;
45
+ exports.isQRAvailableSync = isQRAvailableSync;
46
+ exports.toQRCode = toQRCode;
47
+ exports.toQRCodeDataURL = toQRCodeDataURL;
48
+ exports.toQRCodeSVG = toQRCodeSVG;
49
+ const errors_js_1 = require("../errors.js");
50
+ const specimen_js_1 = require("../specimen.js");
51
+ // Cached reference to the qrcode library
52
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
+ let qrLib = null;
54
+ let qrLibLoadAttempted = false;
55
+ /**
56
+ * Dynamically load the qrcode library.
57
+ * Returns null if the library is not installed.
58
+ */
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ async function loadQRLib() {
61
+ if (qrLibLoadAttempted) {
62
+ return qrLib;
63
+ }
64
+ qrLibLoadAttempted = true;
65
+ try {
66
+ // Dynamic import of optional peer dependency
67
+ const module = await Promise.resolve().then(() => __importStar(require('qrcode')));
68
+ qrLib = module.default ?? module;
69
+ return qrLib;
70
+ }
71
+ catch {
72
+ // qrcode package not installed
73
+ qrLib = null;
74
+ return null;
75
+ }
76
+ }
77
+ /**
78
+ * Ensure qrcode library is available.
79
+ * Throws an error if not installed.
80
+ */
81
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
82
+ async function requireQRLib() {
83
+ const lib = await loadQRLib();
84
+ if (!lib) {
85
+ throw new errors_js_1.WolsError(errors_js_1.WolsErrorCode.UNKNOWN_ERROR, 'QR code generation requires the "qrcode" package. Install it with: npm install qrcode', { missingDependency: 'qrcode' });
86
+ }
87
+ return lib;
88
+ }
89
+ // =============================================================================
90
+ // COMPACT URL FORMAT
91
+ // =============================================================================
92
+ /**
93
+ * Species code mapping for compact URLs.
94
+ */
95
+ const SPECIES_CODES = {
96
+ 'Pleurotus ostreatus': 'POSTR',
97
+ 'Pleurotus citrinopileatus': 'PCITRI',
98
+ 'Pleurotus djamor': 'PDJAR',
99
+ 'Pleurotus eryngii': 'PERYN',
100
+ 'Hericium erinaceus': 'HERIN',
101
+ 'Ganoderma lucidum': 'GLUCI',
102
+ 'Laetiporus pudens': 'LPUDE',
103
+ 'Lentinula edodes': 'LLENC',
104
+ 'Agrocybe polyphylla': 'APOLY',
105
+ 'Stropharia rugosoannulata': 'STRUG',
106
+ };
107
+ /**
108
+ * Growth stage to short code mapping.
109
+ */
110
+ const STAGE_CODES = {
111
+ INOCULATION: 'IN',
112
+ COLONIZATION: 'CO',
113
+ FRUITING: 'FR',
114
+ HARVEST: 'HA',
115
+ };
116
+ /**
117
+ * Convert specimen to compact URL format.
118
+ * Format: wemush://v1/{id}?s={species}&st={stage}&t={timestamp}
119
+ */
120
+ function toCompactUrl(specimen) {
121
+ // Extract the CUID part from the full ID
122
+ const cuidPart = specimen.id.replace('wemush:', '');
123
+ // Build query params
124
+ const params = new URLSearchParams();
125
+ // Add species code
126
+ const speciesCode = SPECIES_CODES[specimen.species];
127
+ if (speciesCode) {
128
+ params.set('s', speciesCode);
129
+ }
130
+ // Add stage if present
131
+ if (specimen.stage) {
132
+ const stageCode = STAGE_CODES[specimen.stage];
133
+ if (stageCode) {
134
+ params.set('st', stageCode);
135
+ }
136
+ }
137
+ // Add timestamp if created is present
138
+ if (specimen.created) {
139
+ const timestamp = Math.floor(new Date(specimen.created).getTime() / 1000);
140
+ params.set('t', String(timestamp));
141
+ }
142
+ const queryString = params.toString();
143
+ return `wemush://v1/${cuidPart}${queryString ? '?' + queryString : ''}`;
144
+ }
145
+ // =============================================================================
146
+ // QR CODE GENERATION
147
+ // =============================================================================
148
+ /**
149
+ * Generate QR code content based on format option.
150
+ */
151
+ function getQRContent(specimen, format) {
152
+ if (format === 'compact') {
153
+ return toCompactUrl(specimen);
154
+ }
155
+ return (0, specimen_js_1.serializeSpecimen)(specimen);
156
+ }
157
+ /**
158
+ * Map QRCodeOptions to library options.
159
+ */
160
+ function mapOptions(options = {}) {
161
+ const result = {
162
+ errorCorrectionLevel: options.errorCorrection ?? 'M',
163
+ width: options.size ?? 300,
164
+ margin: options.margin ?? 1,
165
+ };
166
+ if (options.color) {
167
+ result.color = options.color;
168
+ }
169
+ return result;
170
+ }
171
+ // =============================================================================
172
+ // PUBLIC API
173
+ // =============================================================================
174
+ /**
175
+ * Check if QR code generation is available.
176
+ * Returns true if the qrcode library is installed.
177
+ */
178
+ async function isQRAvailable() {
179
+ const lib = await loadQRLib();
180
+ return lib !== null;
181
+ }
182
+ /**
183
+ * Synchronous check if QR code generation is available.
184
+ * Note: Only accurate after first async call to any QR function.
185
+ */
186
+ function isQRAvailableSync() {
187
+ return qrLib !== null;
188
+ }
189
+ /**
190
+ * Generate QR code as PNG buffer.
191
+ *
192
+ * @param specimen - The specimen to encode
193
+ * @param options - QR code generation options
194
+ * @returns PNG buffer containing the QR code
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const buffer = await toQRCode(specimen, { size: 400 });
199
+ * fs.writeFileSync('specimen-qr.png', buffer);
200
+ * ```
201
+ */
202
+ async function toQRCode(specimen, options = {}) {
203
+ const lib = await requireQRLib();
204
+ const content = getQRContent(specimen, options.format ?? 'embedded');
205
+ const qrOptions = mapOptions(options);
206
+ try {
207
+ return await lib.toBuffer(content, { ...qrOptions, type: 'png' });
208
+ }
209
+ catch (err) {
210
+ const message = err instanceof Error ? err.message : String(err);
211
+ throw new errors_js_1.WolsError(errors_js_1.WolsErrorCode.SIZE_EXCEEDED, `Failed to generate QR code: ${message}`, {
212
+ originalError: message,
213
+ });
214
+ }
215
+ }
216
+ /**
217
+ * Generate QR code as data URL (base64 encoded PNG).
218
+ *
219
+ * @param specimen - The specimen to encode
220
+ * @param options - QR code generation options
221
+ * @returns Data URL string (data:image/png;base64,...)
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * const dataUrl = await toQRCodeDataURL(specimen);
226
+ * // Use in HTML: <img src={dataUrl} />
227
+ * ```
228
+ */
229
+ async function toQRCodeDataURL(specimen, options = {}) {
230
+ const lib = await requireQRLib();
231
+ const content = getQRContent(specimen, options.format ?? 'embedded');
232
+ const qrOptions = mapOptions(options);
233
+ try {
234
+ return await lib.toDataURL(content, qrOptions);
235
+ }
236
+ catch (err) {
237
+ const message = err instanceof Error ? err.message : String(err);
238
+ throw new errors_js_1.WolsError(errors_js_1.WolsErrorCode.SIZE_EXCEEDED, `Failed to generate QR code: ${message}`, {
239
+ originalError: message,
240
+ });
241
+ }
242
+ }
243
+ /**
244
+ * Generate QR code as SVG string.
245
+ *
246
+ * @param specimen - The specimen to encode
247
+ * @param options - QR code generation options
248
+ * @returns SVG string
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * const svg = await toQRCodeSVG(specimen, { color: { dark: '#000', light: '#fff' } });
253
+ * fs.writeFileSync('specimen-qr.svg', svg);
254
+ * ```
255
+ */
256
+ async function toQRCodeSVG(specimen, options = {}) {
257
+ const lib = await requireQRLib();
258
+ const content = getQRContent(specimen, options.format ?? 'embedded');
259
+ const qrOptions = mapOptions(options);
260
+ try {
261
+ const svg = await lib.toString(content, { ...qrOptions, type: 'svg' });
262
+ // Ensure the SVG has proper dimensions based on size option
263
+ const size = options.size ?? 300;
264
+ return svg
265
+ .replace(/width="[^"]*"/, `width="${size}"`)
266
+ .replace(/height="[^"]*"/, `height="${size}"`);
267
+ }
268
+ catch (err) {
269
+ const message = err instanceof Error ? err.message : String(err);
270
+ throw new errors_js_1.WolsError(errors_js_1.WolsErrorCode.SIZE_EXCEEDED, `Failed to generate QR code: ${message}`, {
271
+ originalError: message,
272
+ });
273
+ }
274
+ }
275
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/qr/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * QR Code Submodule
4
+ *
5
+ * This module provides QR code generation functionality for WOLS specimens.
6
+ *
7
+ * @packageDocumentation
8
+ * @module @wemush/wols/qr
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.isQRAvailableSync = exports.isQRAvailable = exports.toQRCodeSVG = exports.toQRCodeDataURL = exports.toQRCode = void 0;
12
+ var generate_js_1 = require("./generate.js");
13
+ Object.defineProperty(exports, "toQRCode", { enumerable: true, get: function () { return generate_js_1.toQRCode; } });
14
+ Object.defineProperty(exports, "toQRCodeDataURL", { enumerable: true, get: function () { return generate_js_1.toQRCodeDataURL; } });
15
+ Object.defineProperty(exports, "toQRCodeSVG", { enumerable: true, get: function () { return generate_js_1.toQRCodeSVG; } });
16
+ Object.defineProperty(exports, "isQRAvailable", { enumerable: true, get: function () { return generate_js_1.isQRAvailable; } });
17
+ Object.defineProperty(exports, "isQRAvailableSync", { enumerable: true, get: function () { return generate_js_1.isQRAvailableSync; } });
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/qr/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,6CAMuB;AALrB,uGAAA,QAAQ,OAAA;AACR,8GAAA,eAAe,OAAA;AACf,0GAAA,WAAW,OAAA;AACX,4GAAA,aAAa,OAAA;AACb,gHAAA,iBAAiB,OAAA"}
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ /**
3
+ * Specimen Creation and Serialization
4
+ *
5
+ * This module provides functions to create and serialize
6
+ * WOLS v1.1.0 compliant specimen objects.
7
+ *
8
+ * @module specimen
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.createSpecimen = createSpecimen;
12
+ exports.serializeSpecimen = serializeSpecimen;
13
+ const types_js_1 = require("./types.js");
14
+ const cuid_js_1 = require("./utils/cuid.js");
15
+ /**
16
+ * Expand a strain input to a full Strain object.
17
+ * String inputs are expanded to { name: string }.
18
+ *
19
+ * @param strain - String or Strain object input
20
+ * @returns Strain object or undefined
21
+ */
22
+ function expandStrain(strain) {
23
+ if (strain === undefined) {
24
+ return undefined;
25
+ }
26
+ if (typeof strain === 'string') {
27
+ return { name: strain };
28
+ }
29
+ if ((0, types_js_1.isStrain)(strain)) {
30
+ return strain;
31
+ }
32
+ return undefined;
33
+ }
34
+ /**
35
+ * Create a new specimen with auto-generated ID and JSON-LD fields.
36
+ *
37
+ * This function creates a fully-formed WOLS v1.1.0 compliant Specimen
38
+ * with automatic ID generation, version assignment, and JSON-LD context.
39
+ *
40
+ * @param input - Specimen creation parameters
41
+ * @returns Fully-formed Specimen with JSON-LD fields
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * // Minimal specimen
46
+ * const culture = createSpecimen({
47
+ * type: 'CULTURE',
48
+ * species: 'Pleurotus ostreatus',
49
+ * });
50
+ *
51
+ * // Full specimen with strain info
52
+ * const substrate = createSpecimen({
53
+ * type: 'SUBSTRATE',
54
+ * species: 'Hericium erinaceus',
55
+ * strain: {
56
+ * name: "Lion's Mane Premium",
57
+ * generation: 'F2',
58
+ * clonalGeneration: 3,
59
+ * },
60
+ * stage: 'COLONIZATION',
61
+ * batch: 'batch_2025_12_001',
62
+ * organization: 'org_mushoh',
63
+ * });
64
+ *
65
+ * // String strain shorthand
66
+ * const spawn = createSpecimen({
67
+ * type: 'SPAWN',
68
+ * species: 'Ganoderma lucidum',
69
+ * strain: 'Reishi Red', // Auto-expands to { name: 'Reishi Red' }
70
+ * });
71
+ * ```
72
+ */
73
+ function createSpecimen(input) {
74
+ const id = (0, types_js_1.asSpecimenId)((0, cuid_js_1.createSpecimenId)());
75
+ const strain = expandStrain(input.strain);
76
+ // Build specimen with required fields
77
+ const specimen = {
78
+ '@context': types_js_1.WOLS_CONTEXT,
79
+ '@type': 'Specimen',
80
+ id,
81
+ version: types_js_1.WOLS_VERSION,
82
+ type: input.type,
83
+ species: input.species,
84
+ };
85
+ // Add optional fields only if defined
86
+ if (strain !== undefined) {
87
+ specimen.strain = strain;
88
+ }
89
+ if (input.stage !== undefined) {
90
+ specimen.stage = input.stage;
91
+ }
92
+ if (input.batch !== undefined) {
93
+ specimen.batch = input.batch;
94
+ }
95
+ if (input.organization !== undefined) {
96
+ specimen.organization = input.organization;
97
+ }
98
+ if (input.creator !== undefined) {
99
+ specimen.creator = input.creator;
100
+ }
101
+ if (input.custom !== undefined) {
102
+ specimen.custom = input.custom;
103
+ }
104
+ return specimen;
105
+ }
106
+ /**
107
+ * Serialize a specimen to JSON-LD string.
108
+ *
109
+ * The output is formatted with JSON-LD fields (@context, @type) first,
110
+ * followed by id, version, and remaining fields. Undefined fields are omitted.
111
+ *
112
+ * @param specimen - Specimen to serialize
113
+ * @returns JSON string suitable for QR encoding
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const specimen = createSpecimen({
118
+ * type: 'CULTURE',
119
+ * species: 'Pleurotus ostreatus',
120
+ * });
121
+ *
122
+ * const json = serializeSpecimen(specimen);
123
+ * // Returns: '{"@context":"https://wemush.com/wols/v1","@type":"Specimen",...}'
124
+ * ```
125
+ */
126
+ function serializeSpecimen(specimen) {
127
+ // Build ordered object with JSON-LD fields first
128
+ const ordered = {
129
+ '@context': specimen['@context'],
130
+ '@type': specimen['@type'],
131
+ id: specimen.id,
132
+ version: specimen.version,
133
+ type: specimen.type,
134
+ species: specimen.species,
135
+ };
136
+ // Add optional fields in order, only if defined
137
+ if (specimen.strain !== undefined) {
138
+ ordered['strain'] = specimen.strain;
139
+ }
140
+ if (specimen.stage !== undefined) {
141
+ ordered['stage'] = specimen.stage;
142
+ }
143
+ if (specimen.created !== undefined) {
144
+ ordered['created'] = specimen.created;
145
+ }
146
+ if (specimen.batch !== undefined) {
147
+ ordered['batch'] = specimen.batch;
148
+ }
149
+ if (specimen.organization !== undefined) {
150
+ ordered['organization'] = specimen.organization;
151
+ }
152
+ if (specimen.creator !== undefined) {
153
+ ordered['creator'] = specimen.creator;
154
+ }
155
+ if (specimen.custom !== undefined) {
156
+ ordered['custom'] = specimen.custom;
157
+ }
158
+ if (specimen.signature !== undefined) {
159
+ ordered['signature'] = specimen.signature;
160
+ }
161
+ return JSON.stringify(ordered);
162
+ }
163
+ //# sourceMappingURL=specimen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specimen.js","sourceRoot":"","sources":["../../src/specimen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * WOLS TypeScript Library - Core Types
4
+ *
5
+ * This module defines all the core types, interfaces, and enums
6
+ * for the WeMush Open Labeling Standard (WOLS) v1.1.0.
7
+ *
8
+ * @packageDocumentation
9
+ * @module @wemush/wols
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.GROWTH_STAGES = exports.SPECIMEN_TYPES = exports.WOLS_CONTEXT = exports.WOLS_VERSION = void 0;
13
+ exports.asSpecimenId = asSpecimenId;
14
+ exports.isSpecimenType = isSpecimenType;
15
+ exports.isGrowthStage = isGrowthStage;
16
+ exports.isStrain = isStrain;
17
+ // =============================================================================
18
+ // CONSTANTS
19
+ // =============================================================================
20
+ /**
21
+ * WOLS specification version implemented by this library.
22
+ */
23
+ exports.WOLS_VERSION = '1.1.0';
24
+ /**
25
+ * JSON-LD context URL for WOLS specimens.
26
+ */
27
+ exports.WOLS_CONTEXT = 'https://wemush.com/wols/v1';
28
+ /**
29
+ * Create a SpecimenId from a string.
30
+ * Does not validate the format - use isValidSpecimenId for validation.
31
+ */
32
+ function asSpecimenId(id) {
33
+ return id;
34
+ }
35
+ /**
36
+ * Array of valid specimen types for validation.
37
+ */
38
+ exports.SPECIMEN_TYPES = [
39
+ 'CULTURE',
40
+ 'SPAWN',
41
+ 'SUBSTRATE',
42
+ 'FRUITING',
43
+ 'HARVEST',
44
+ ];
45
+ /**
46
+ * Array of valid growth stages for validation.
47
+ */
48
+ exports.GROWTH_STAGES = [
49
+ 'INOCULATION',
50
+ 'COLONIZATION',
51
+ 'FRUITING',
52
+ 'HARVEST',
53
+ ];
54
+ // =============================================================================
55
+ // TYPE GUARDS
56
+ // =============================================================================
57
+ /**
58
+ * Type guard to check if a value is a valid SpecimenType.
59
+ */
60
+ function isSpecimenType(value) {
61
+ return typeof value === 'string' && exports.SPECIMEN_TYPES.includes(value);
62
+ }
63
+ /**
64
+ * Type guard to check if a value is a valid GrowthStage.
65
+ */
66
+ function isGrowthStage(value) {
67
+ return typeof value === 'string' && exports.GROWTH_STAGES.includes(value);
68
+ }
69
+ /**
70
+ * Type guard to check if a value is a Strain object.
71
+ */
72
+ function isStrain(value) {
73
+ return (typeof value === 'object' &&
74
+ value !== null &&
75
+ 'name' in value &&
76
+ typeof value.name === 'string');
77
+ }
78
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAoCH,oCAEC;AA0RD,wCAEC;AAKD,sCAEC;AAKD,4BAOC;AAnVD,gFAAgF;AAChF,YAAY;AACZ,gFAAgF;AAEhF;;GAEG;AACU,QAAA,YAAY,GAAG,OAAO,CAAC;AAEpC;;GAEG;AACU,QAAA,YAAY,GAAG,4BAA4B,CAAC;AAkBzD;;;GAGG;AACH,SAAgB,YAAY,CAAC,EAAU;IACrC,OAAO,EAAgB,CAAC;AAC1B,CAAC;AAWD;;GAEG;AACU,QAAA,cAAc,GAA4B;IACrD,SAAS;IACT,OAAO;IACP,WAAW;IACX,UAAU;IACV,SAAS;CACD,CAAC;AAOX;;GAEG;AACU,QAAA,aAAa,GAA2B;IACnD,aAAa;IACb,cAAc;IACd,UAAU;IACV,SAAS;CACD,CAAC;AAgPX,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;GAEG;AACH,SAAgB,cAAc,CAAC,KAAc;IAC3C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,sBAAc,CAAC,QAAQ,CAAC,KAAqB,CAAC,CAAC;AACrF,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAAC,KAAc;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,qBAAa,CAAC,QAAQ,CAAC,KAAoB,CAAC,CAAC;AACnF,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,KAAc;IACrC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,MAAM,IAAI,KAAK;QACf,OAAQ,KAAgB,CAAC,IAAI,KAAK,QAAQ,CAC3C,CAAC;AACJ,CAAC"}