@resourcexjs/core 2.14.1 → 2.16.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.
- package/dist/index.d.ts +42 -68
- package/dist/index.js +120 -64
- package/dist/index.js.map +17 -16
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -72,18 +72,21 @@ interface RXI {
|
|
|
72
72
|
readonly path?: string;
|
|
73
73
|
/** Resource name */
|
|
74
74
|
readonly name: string;
|
|
75
|
-
/** Tag (
|
|
75
|
+
/** Tag (mutable pointer). Defaults to "latest" if not specified. */
|
|
76
76
|
readonly tag: string;
|
|
77
|
+
/** Content digest (immutable hash, e.g., "sha256:abc123"). */
|
|
78
|
+
readonly digest?: string;
|
|
77
79
|
}
|
|
78
80
|
/**
|
|
79
81
|
* Format RXI to locator string.
|
|
80
82
|
*
|
|
81
|
-
* Docker-style format: [registry/][path/]name[:tag]
|
|
83
|
+
* Docker-style format: [registry/][path/]name[:tag][@digest]
|
|
82
84
|
*
|
|
83
85
|
* Examples:
|
|
84
86
|
* - { name: "hello", tag: "latest" } → "hello" (omit :latest)
|
|
85
87
|
* - { name: "hello", tag: "1.0.0" } → "hello:1.0.0"
|
|
86
|
-
* - {
|
|
88
|
+
* - { name: "hello", tag: "latest", digest: "sha256:abc" } → "hello@sha256:abc"
|
|
89
|
+
* - { name: "hello", tag: "beta", digest: "sha256:abc" } → "hello:beta@sha256:abc"
|
|
87
90
|
*
|
|
88
91
|
* @param rxi - Resource identifier
|
|
89
92
|
* @returns Locator string
|
|
@@ -113,9 +116,11 @@ interface RXMDefinition {
|
|
|
113
116
|
}
|
|
114
117
|
/**
|
|
115
118
|
* RXM Archive — packaging metadata.
|
|
116
|
-
* Placeholder for future fields (digest, size, md5, etc.)
|
|
117
119
|
*/
|
|
118
|
-
|
|
120
|
+
interface RXMArchive {
|
|
121
|
+
/** Deterministic content digest computed from file-level digests. Format: sha256:<hex> */
|
|
122
|
+
readonly digest?: string;
|
|
123
|
+
}
|
|
119
124
|
/**
|
|
120
125
|
* File entry with metadata.
|
|
121
126
|
*/
|
|
@@ -242,7 +247,7 @@ interface TypeDetectionResult {
|
|
|
242
247
|
readonly type: string;
|
|
243
248
|
/** Detected resource name */
|
|
244
249
|
readonly name: string;
|
|
245
|
-
/** Tag
|
|
250
|
+
/** Tag (defaults to "latest" if not provided) */
|
|
246
251
|
readonly tag?: string;
|
|
247
252
|
/** Description extracted from content */
|
|
248
253
|
readonly description?: string;
|
|
@@ -293,6 +298,17 @@ interface TypeDetector {
|
|
|
293
298
|
*/
|
|
294
299
|
declare function generateDefinition(result: TypeDetectionResult): RXD;
|
|
295
300
|
/**
|
|
301
|
+
* PrototypeDetector - Detects prototype resources from prototype.json.
|
|
302
|
+
*
|
|
303
|
+
* Pattern:
|
|
304
|
+
* - Required: prototype.json file
|
|
305
|
+
* - Optional: *.feature files (referenced via @filename)
|
|
306
|
+
*/
|
|
307
|
+
declare class PrototypeDetector implements TypeDetector {
|
|
308
|
+
readonly name = "prototype";
|
|
309
|
+
detect(files: Record<string, Buffer>, source: string): TypeDetectionResult | null;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
296
312
|
* ResourceJsonDetector - Detects resources with an explicit resource.json.
|
|
297
313
|
*
|
|
298
314
|
* Highest-priority detector. When resource.json exists,
|
|
@@ -330,7 +346,8 @@ declare class SkillDetector implements TypeDetector {
|
|
|
330
346
|
* Detection order:
|
|
331
347
|
* 1. ResourceJsonDetector (explicit resource.json always wins)
|
|
332
348
|
* 2. SkillDetector (SKILL.md pattern)
|
|
333
|
-
* 3.
|
|
349
|
+
* 3. PrototypeDetector (prototype.json pattern)
|
|
350
|
+
* 4. Custom detectors (registered in order)
|
|
334
351
|
*/
|
|
335
352
|
declare class TypeDetectorChain {
|
|
336
353
|
private readonly detectors;
|
|
@@ -415,21 +432,6 @@ interface SourceLoader {
|
|
|
415
432
|
* @throws ResourceXError if loading fails
|
|
416
433
|
*/
|
|
417
434
|
load(source: string): Promise<RXS>;
|
|
418
|
-
/**
|
|
419
|
-
* Check if cached content for this source is still fresh.
|
|
420
|
-
*
|
|
421
|
-
* Each loader implements its own strategy:
|
|
422
|
-
* - FolderSourceLoader: compare file mtime against cachedAt
|
|
423
|
-
* - GitHubSourceLoader: not implemented (always stale)
|
|
424
|
-
*
|
|
425
|
-
* Loaders that don't implement this are treated as always stale,
|
|
426
|
-
* causing a full reload on every ingest.
|
|
427
|
-
*
|
|
428
|
-
* @param source - Source path or identifier
|
|
429
|
-
* @param cachedAt - When the resource was last cached
|
|
430
|
-
* @returns true if cache is still fresh, false if stale
|
|
431
|
-
*/
|
|
432
|
-
isFresh?(source: string, cachedAt: Date): Promise<boolean>;
|
|
433
435
|
}
|
|
434
436
|
/**
|
|
435
437
|
* Default ResourceLoader implementation for loading resources from folders.
|
|
@@ -446,8 +448,8 @@ interface SourceLoader {
|
|
|
446
448
|
* {
|
|
447
449
|
* "name": "resource-name", // required
|
|
448
450
|
* "type": "text", // required
|
|
449
|
-
* "
|
|
450
|
-
* "
|
|
451
|
+
* "tag": "1.0.0", // optional, defaults to "latest"
|
|
452
|
+
* "registry": "localhost", // optional
|
|
451
453
|
* "path": "optional/path" // optional
|
|
452
454
|
* }
|
|
453
455
|
* ```
|
|
@@ -473,15 +475,6 @@ declare class FolderSourceLoader implements SourceLoader {
|
|
|
473
475
|
canLoad(source: string): Promise<boolean>;
|
|
474
476
|
load(source: string): Promise<RXS>;
|
|
475
477
|
/**
|
|
476
|
-
* Check if cached content is still fresh by comparing file mtimes.
|
|
477
|
-
* Returns true only if no file in the directory has been modified since cachedAt.
|
|
478
|
-
*/
|
|
479
|
-
isFresh(source: string, cachedAt: Date): Promise<boolean>;
|
|
480
|
-
/**
|
|
481
|
-
* Get the most recent mtime across all files in a folder (recursive).
|
|
482
|
-
*/
|
|
483
|
-
private getMaxMtime;
|
|
484
|
-
/**
|
|
485
478
|
* Recursively read all files in a folder.
|
|
486
479
|
*/
|
|
487
480
|
private readFolderFiles;
|
|
@@ -584,17 +577,6 @@ declare class SourceLoaderChain {
|
|
|
584
577
|
* @throws ResourceXError if no loader matches
|
|
585
578
|
*/
|
|
586
579
|
load(source: string): Promise<RXS>;
|
|
587
|
-
/**
|
|
588
|
-
* Check if cached content for a source is still fresh.
|
|
589
|
-
*
|
|
590
|
-
* Delegates to the matching loader's isFresh method.
|
|
591
|
-
* Returns false if the loader doesn't implement isFresh (always reload).
|
|
592
|
-
*
|
|
593
|
-
* @param source - Source path or identifier
|
|
594
|
-
* @param cachedAt - When the resource was last cached
|
|
595
|
-
* @returns true if cache is still fresh
|
|
596
|
-
*/
|
|
597
|
-
isFresh(source: string, cachedAt: Date): Promise<boolean>;
|
|
598
580
|
}
|
|
599
581
|
/**
|
|
600
582
|
* Configuration for resolveSource.
|
|
@@ -684,6 +666,7 @@ interface StoredRXM {
|
|
|
684
666
|
readonly license?: string;
|
|
685
667
|
readonly keywords?: string[];
|
|
686
668
|
readonly repository?: string;
|
|
669
|
+
readonly digest?: string;
|
|
687
670
|
readonly files: Record<string, string>;
|
|
688
671
|
readonly createdAt?: Date;
|
|
689
672
|
readonly updatedAt?: Date;
|
|
@@ -778,19 +761,6 @@ interface ProviderStores {
|
|
|
778
761
|
rxmStore: RXMStore;
|
|
779
762
|
}
|
|
780
763
|
/**
|
|
781
|
-
* Resource loader interface for loading from directories/archives.
|
|
782
|
-
*/
|
|
783
|
-
interface ResourceLoader2 {
|
|
784
|
-
/**
|
|
785
|
-
* Check if this loader can handle the given source.
|
|
786
|
-
*/
|
|
787
|
-
canLoad(source: string): boolean | Promise<boolean>;
|
|
788
|
-
/**
|
|
789
|
-
* Load resource from source.
|
|
790
|
-
*/
|
|
791
|
-
load(source: string): Promise<unknown>;
|
|
792
|
-
}
|
|
793
|
-
/**
|
|
794
764
|
* Platform-specific defaults resolved from environment variables and config files.
|
|
795
765
|
*/
|
|
796
766
|
interface ProviderDefaults {
|
|
@@ -823,11 +793,6 @@ interface ResourceXProvider {
|
|
|
823
793
|
*/
|
|
824
794
|
createStores(config: ProviderConfig): ProviderStores;
|
|
825
795
|
/**
|
|
826
|
-
* Create resource loader (optional).
|
|
827
|
-
* Not all platforms support loading from filesystem.
|
|
828
|
-
*/
|
|
829
|
-
createLoader?(config: ProviderConfig): ResourceLoader2;
|
|
830
|
-
/**
|
|
831
796
|
* Create source loader for auto-detection pipeline (optional).
|
|
832
797
|
*/
|
|
833
798
|
createSourceLoader?(config: ProviderConfig): SourceLoader;
|
|
@@ -915,8 +880,9 @@ interface Registry {
|
|
|
915
880
|
get(rxi: RXI): Promise<RXR>;
|
|
916
881
|
/**
|
|
917
882
|
* Store resource.
|
|
883
|
+
* @returns The stored manifest (with computed digest).
|
|
918
884
|
*/
|
|
919
|
-
put(rxr: RXR): Promise<
|
|
885
|
+
put(rxr: RXR): Promise<RXM>;
|
|
920
886
|
/**
|
|
921
887
|
* Check if resource exists.
|
|
922
888
|
*/
|
|
@@ -936,7 +902,7 @@ declare class CASRegistry implements Registry {
|
|
|
936
902
|
constructor(rxaStore: RXAStore, rxmStore: RXMStore);
|
|
937
903
|
private resolveTag;
|
|
938
904
|
get(rxi: RXI): Promise<RXR>;
|
|
939
|
-
put(rxr: RXR): Promise<
|
|
905
|
+
put(rxr: RXR): Promise<RXM>;
|
|
940
906
|
has(rxi: RXI): Promise<boolean>;
|
|
941
907
|
remove(rxi: RXI): Promise<void>;
|
|
942
908
|
list(options?: SearchOptions): Promise<RXI[]>;
|
|
@@ -994,7 +960,7 @@ declare class LinkedRegistry implements Registry {
|
|
|
994
960
|
* Put is not typically used for LinkedRegistry.
|
|
995
961
|
* Use link() instead to create symlinks.
|
|
996
962
|
*/
|
|
997
|
-
put(_rxr: RXR): Promise<
|
|
963
|
+
put(_rxr: RXR): Promise<RXM>;
|
|
998
964
|
has(rxi: RXI): Promise<boolean>;
|
|
999
965
|
remove(rxi: RXI): Promise<void>;
|
|
1000
966
|
list(options?: SearchOptions): Promise<RXI[]>;
|
|
@@ -1030,7 +996,7 @@ declare abstract class RegistryMiddleware implements Registry {
|
|
|
1030
996
|
protected readonly inner: Registry;
|
|
1031
997
|
constructor(inner: Registry);
|
|
1032
998
|
get(rxi: RXI): Promise<RXR>;
|
|
1033
|
-
put(rxr: RXR): Promise<
|
|
999
|
+
put(rxr: RXR): Promise<RXM>;
|
|
1034
1000
|
has(rxi: RXI): Promise<boolean>;
|
|
1035
1001
|
remove(rxi: RXI): Promise<void>;
|
|
1036
1002
|
list(options?: SearchOptions): Promise<RXI[]>;
|
|
@@ -1129,7 +1095,7 @@ interface ResolveContext {
|
|
|
1129
1095
|
path?: string
|
|
1130
1096
|
name: string
|
|
1131
1097
|
type: string
|
|
1132
|
-
|
|
1098
|
+
tag: string
|
|
1133
1099
|
};
|
|
1134
1100
|
/**
|
|
1135
1101
|
* Extracted files from archive.
|
|
@@ -1265,6 +1231,14 @@ declare const jsonType: BundledType;
|
|
|
1265
1231
|
*/
|
|
1266
1232
|
declare const binaryType: BundledType;
|
|
1267
1233
|
/**
|
|
1234
|
+
* Skill content (SKILL.md + optional references)
|
|
1235
|
+
*/
|
|
1236
|
+
declare const skillType: BundledType;
|
|
1237
|
+
/**
|
|
1238
|
+
* Prototype instruction set (prototype.json + @filename references)
|
|
1239
|
+
*/
|
|
1240
|
+
declare const prototypeType: BundledType;
|
|
1241
|
+
/**
|
|
1268
1242
|
* All built-in types as an array.
|
|
1269
1243
|
*/
|
|
1270
1244
|
declare const builtinTypes: BundledType[];
|
|
@@ -1337,4 +1311,4 @@ declare class TypeHandlerChain {
|
|
|
1337
1311
|
*/
|
|
1338
1312
|
clear(): void;
|
|
1339
1313
|
}
|
|
1340
|
-
export { wrap, withDomainValidation, textType, resource, resolveSource, parse, manifest, locate, loadResource, jsonType, isValidDigest, generateDefinition, format, extract, discoverRegistry, define, computeDigest, bundleResourceType, builtinTypes, binaryType, archive, WellKnownResponse, TypeHandlerChain, TypeDetectorChain, TypeDetector, TypeDetectionResult, StoredRXM, SourceLoaderChain, SourceLoader, SkillDetector, SearchOptions, ResourceXProvider, ResourceXError, ResourceTypeError, ResourceType, ResourceResolver, ResourceLoader, ResourceJsonDetector, ResolvedResource, ResolveSourceConfig, ResolveContext, RegistryMiddleware, RegistryError, RegistryEntry, Registry, RXS, RXR, RXMStore, RXMSource, RXMSearchOptions, RXMDefinition, RXMArchive, RXM, RXL, RXI, RXD, RXAStore, RXA, ProviderStores, ProviderDefaults, ProviderConfig, MemoryRXMStore, MemoryRXAStore, ManifestError, LocatorError, LoadResourceConfig, LinkedRegistry, JSONSchemaProperty, JSONSchema, IsolatorType, GitHubSourceLoader, FolderSourceLoader, FolderLoader, FileTree, FileEntry, DomainValidation, DiscoveryResult, DefinitionError, ContentError, CASRegistry, BundledType };
|
|
1314
|
+
export { wrap, withDomainValidation, textType, skillType, resource, resolveSource, prototypeType, parse, manifest, locate, loadResource, jsonType, isValidDigest, generateDefinition, format, extract, discoverRegistry, define, computeDigest, bundleResourceType, builtinTypes, binaryType, archive, WellKnownResponse, TypeHandlerChain, TypeDetectorChain, TypeDetector, TypeDetectionResult, StoredRXM, SourceLoaderChain, SourceLoader, SkillDetector, SearchOptions, ResourceXProvider, ResourceXError, ResourceTypeError, ResourceType, ResourceResolver, ResourceLoader, ResourceJsonDetector, ResolvedResource, ResolveSourceConfig, ResolveContext, RegistryMiddleware, RegistryError, RegistryEntry, Registry, RXS, RXR, RXMStore, RXMSource, RXMSearchOptions, RXMDefinition, RXMArchive, RXM, RXL, RXI, RXD, RXAStore, RXA, ProviderStores, ProviderDefaults, ProviderConfig, PrototypeDetector, MemoryRXMStore, MemoryRXAStore, ManifestError, LocatorError, LoadResourceConfig, LinkedRegistry, JSONSchemaProperty, JSONSchema, IsolatorType, GitHubSourceLoader, FolderSourceLoader, FolderLoader, FileTree, FileEntry, DomainValidation, DiscoveryResult, DefinitionError, ContentError, CASRegistry, BundledType };
|
package/dist/index.js
CHANGED
|
@@ -14597,7 +14597,6 @@ var RXDSchema = exports_external.object({
|
|
|
14597
14597
|
name: exports_external.string().min(1).max(128),
|
|
14598
14598
|
type: exports_external.string().min(1).max(64),
|
|
14599
14599
|
tag: exports_external.string().max(64).optional(),
|
|
14600
|
-
version: exports_external.string().max(64).optional(),
|
|
14601
14600
|
registry: exports_external.string().max(256).optional(),
|
|
14602
14601
|
path: exports_external.string().max(256).optional(),
|
|
14603
14602
|
description: exports_external.string().max(1024).optional(),
|
|
@@ -14619,7 +14618,7 @@ function define(input) {
|
|
|
14619
14618
|
const rxd = Object.assign(Object.create(null), {
|
|
14620
14619
|
name: validated.name,
|
|
14621
14620
|
type: validated.type,
|
|
14622
|
-
tag: validated.tag ??
|
|
14621
|
+
tag: validated.tag ?? undefined,
|
|
14623
14622
|
registry: validated.registry,
|
|
14624
14623
|
path: validated.path,
|
|
14625
14624
|
description: validated.description,
|
|
@@ -14659,6 +14658,9 @@ function format(rxi) {
|
|
|
14659
14658
|
if (rxi.tag && rxi.tag !== "latest") {
|
|
14660
14659
|
result += `:${rxi.tag}`;
|
|
14661
14660
|
}
|
|
14661
|
+
if (rxi.digest) {
|
|
14662
|
+
result += `@${rxi.digest}`;
|
|
14663
|
+
}
|
|
14662
14664
|
return result;
|
|
14663
14665
|
}
|
|
14664
14666
|
// src/model/locate.ts
|
|
@@ -14737,15 +14739,25 @@ function parse5(locator) {
|
|
|
14737
14739
|
throw new LocatorError("Locator must be a non-empty string", locator);
|
|
14738
14740
|
}
|
|
14739
14741
|
validateLocatorSecurity(locator);
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
+
let digest;
|
|
14743
|
+
let locatorWithoutDigest = locator;
|
|
14744
|
+
const atIndex = locator.indexOf("@");
|
|
14745
|
+
if (atIndex !== -1) {
|
|
14746
|
+
if (atIndex === 0) {
|
|
14747
|
+
throw new LocatorError("Invalid locator format. Name is required before @", locator);
|
|
14748
|
+
}
|
|
14749
|
+
digest = locator.substring(atIndex + 1);
|
|
14750
|
+
locatorWithoutDigest = locator.substring(0, atIndex);
|
|
14751
|
+
if (!digest || digest.includes("@")) {
|
|
14752
|
+
throw new LocatorError("Invalid digest format after @", locator);
|
|
14753
|
+
}
|
|
14742
14754
|
}
|
|
14743
|
-
const lastSlashIndex =
|
|
14755
|
+
const lastSlashIndex = locatorWithoutDigest.lastIndexOf("/");
|
|
14744
14756
|
let beforeSlash = "";
|
|
14745
|
-
let afterSlash =
|
|
14757
|
+
let afterSlash = locatorWithoutDigest;
|
|
14746
14758
|
if (lastSlashIndex !== -1) {
|
|
14747
|
-
beforeSlash =
|
|
14748
|
-
afterSlash =
|
|
14759
|
+
beforeSlash = locatorWithoutDigest.substring(0, lastSlashIndex);
|
|
14760
|
+
afterSlash = locatorWithoutDigest.substring(lastSlashIndex + 1);
|
|
14749
14761
|
}
|
|
14750
14762
|
const colonIndex = afterSlash.lastIndexOf(":");
|
|
14751
14763
|
let name;
|
|
@@ -14768,7 +14780,8 @@ function parse5(locator) {
|
|
|
14768
14780
|
registry: undefined,
|
|
14769
14781
|
path: undefined,
|
|
14770
14782
|
name,
|
|
14771
|
-
tag
|
|
14783
|
+
tag,
|
|
14784
|
+
digest
|
|
14772
14785
|
};
|
|
14773
14786
|
}
|
|
14774
14787
|
const parts = beforeSlash.split("/");
|
|
@@ -14779,14 +14792,16 @@ function parse5(locator) {
|
|
|
14779
14792
|
registry: registry2,
|
|
14780
14793
|
path,
|
|
14781
14794
|
name,
|
|
14782
|
-
tag
|
|
14795
|
+
tag,
|
|
14796
|
+
digest
|
|
14783
14797
|
};
|
|
14784
14798
|
}
|
|
14785
14799
|
return {
|
|
14786
14800
|
registry: undefined,
|
|
14787
14801
|
path: beforeSlash,
|
|
14788
14802
|
name,
|
|
14789
|
-
tag
|
|
14803
|
+
tag,
|
|
14804
|
+
digest
|
|
14790
14805
|
};
|
|
14791
14806
|
}
|
|
14792
14807
|
// src/model/resource.ts
|
|
@@ -14844,6 +14859,23 @@ function generateDefinition(result) {
|
|
|
14844
14859
|
input.repository = result.repository;
|
|
14845
14860
|
return define(input);
|
|
14846
14861
|
}
|
|
14862
|
+
// src/detector/PrototypeDetector.ts
|
|
14863
|
+
import { basename } from "node:path";
|
|
14864
|
+
|
|
14865
|
+
class PrototypeDetector {
|
|
14866
|
+
name = "prototype";
|
|
14867
|
+
detect(files, source) {
|
|
14868
|
+
if (!files["prototype.json"]) {
|
|
14869
|
+
return null;
|
|
14870
|
+
}
|
|
14871
|
+
const name = basename(source);
|
|
14872
|
+
return {
|
|
14873
|
+
type: "prototype",
|
|
14874
|
+
name,
|
|
14875
|
+
description: `Prototype instruction set: ${name}`
|
|
14876
|
+
};
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14847
14879
|
// src/detector/ResourceJsonDetector.ts
|
|
14848
14880
|
class ResourceJsonDetector {
|
|
14849
14881
|
name = "resource-json";
|
|
@@ -14864,7 +14896,7 @@ class ResourceJsonDetector {
|
|
|
14864
14896
|
return {
|
|
14865
14897
|
type: json2.type,
|
|
14866
14898
|
name: json2.name,
|
|
14867
|
-
tag: json2.tag
|
|
14899
|
+
tag: json2.tag,
|
|
14868
14900
|
description: json2.description,
|
|
14869
14901
|
registry: json2.registry,
|
|
14870
14902
|
path: json2.path,
|
|
@@ -14877,7 +14909,7 @@ class ResourceJsonDetector {
|
|
|
14877
14909
|
}
|
|
14878
14910
|
}
|
|
14879
14911
|
// src/detector/SkillDetector.ts
|
|
14880
|
-
import { basename } from "node:path";
|
|
14912
|
+
import { basename as basename2 } from "node:path";
|
|
14881
14913
|
|
|
14882
14914
|
class SkillDetector {
|
|
14883
14915
|
name = "skill";
|
|
@@ -14885,7 +14917,7 @@ class SkillDetector {
|
|
|
14885
14917
|
if (!files["SKILL.md"]) {
|
|
14886
14918
|
return null;
|
|
14887
14919
|
}
|
|
14888
|
-
const name =
|
|
14920
|
+
const name = basename2(source);
|
|
14889
14921
|
const content = files["SKILL.md"].toString("utf-8");
|
|
14890
14922
|
const description = this.extractDescription(content);
|
|
14891
14923
|
return {
|
|
@@ -14914,6 +14946,7 @@ class TypeDetectorChain {
|
|
|
14914
14946
|
const chain = new TypeDetectorChain;
|
|
14915
14947
|
chain.detectors.push(new ResourceJsonDetector);
|
|
14916
14948
|
chain.detectors.push(new SkillDetector);
|
|
14949
|
+
chain.detectors.push(new PrototypeDetector);
|
|
14917
14950
|
return chain;
|
|
14918
14951
|
}
|
|
14919
14952
|
register(detector) {
|
|
@@ -15008,31 +15041,6 @@ class FolderSourceLoader {
|
|
|
15008
15041
|
const files = await this.readFolderFiles(source);
|
|
15009
15042
|
return { source, files };
|
|
15010
15043
|
}
|
|
15011
|
-
async isFresh(source, cachedAt) {
|
|
15012
|
-
try {
|
|
15013
|
-
const maxMtime = await this.getMaxMtime(source);
|
|
15014
|
-
return maxMtime <= cachedAt;
|
|
15015
|
-
} catch {
|
|
15016
|
-
return false;
|
|
15017
|
-
}
|
|
15018
|
-
}
|
|
15019
|
-
async getMaxMtime(folderPath) {
|
|
15020
|
-
let max = new Date(0);
|
|
15021
|
-
const entries = await readdir2(folderPath, { withFileTypes: true });
|
|
15022
|
-
for (const entry of entries) {
|
|
15023
|
-
const fullPath = join2(folderPath, entry.name);
|
|
15024
|
-
if (entry.isFile()) {
|
|
15025
|
-
const stats = await stat2(fullPath);
|
|
15026
|
-
if (stats.mtime > max)
|
|
15027
|
-
max = stats.mtime;
|
|
15028
|
-
} else if (entry.isDirectory()) {
|
|
15029
|
-
const subMax = await this.getMaxMtime(fullPath);
|
|
15030
|
-
if (subMax > max)
|
|
15031
|
-
max = subMax;
|
|
15032
|
-
}
|
|
15033
|
-
}
|
|
15034
|
-
return max;
|
|
15035
|
-
}
|
|
15036
15044
|
async readFolderFiles(folderPath, basePath = folderPath) {
|
|
15037
15045
|
const files = {};
|
|
15038
15046
|
const entries = await readdir2(folderPath, { withFileTypes: true });
|
|
@@ -15154,17 +15162,6 @@ class SourceLoaderChain {
|
|
|
15154
15162
|
}
|
|
15155
15163
|
throw new ResourceXError(`Cannot load source: ${source}`);
|
|
15156
15164
|
}
|
|
15157
|
-
async isFresh(source, cachedAt) {
|
|
15158
|
-
for (const loader of this.loaders) {
|
|
15159
|
-
if (await loader.canLoad(source)) {
|
|
15160
|
-
if (loader.isFresh) {
|
|
15161
|
-
return loader.isFresh(source, cachedAt);
|
|
15162
|
-
}
|
|
15163
|
-
return false;
|
|
15164
|
-
}
|
|
15165
|
-
}
|
|
15166
|
-
return false;
|
|
15167
|
-
}
|
|
15168
15165
|
}
|
|
15169
15166
|
|
|
15170
15167
|
// src/loader/resolveSource.ts
|
|
@@ -15278,6 +15275,22 @@ function withRegistryValidation(registry2, trustedRegistry) {
|
|
|
15278
15275
|
}
|
|
15279
15276
|
var DomainValidation = RegistryValidation;
|
|
15280
15277
|
var withDomainValidation = withRegistryValidation;
|
|
15278
|
+
// src/registry/store/digest.ts
|
|
15279
|
+
import { createHash } from "node:crypto";
|
|
15280
|
+
function computeDigest(data) {
|
|
15281
|
+
const hash2 = createHash("sha256").update(data).digest("hex");
|
|
15282
|
+
return `sha256:${hash2}`;
|
|
15283
|
+
}
|
|
15284
|
+
function computeArchiveDigest(files) {
|
|
15285
|
+
const entries = Object.keys(files).sort().map((name) => `${name}:${files[name]}`).join(`
|
|
15286
|
+
`);
|
|
15287
|
+
const hash2 = createHash("sha256").update(entries).digest("hex");
|
|
15288
|
+
return `sha256:${hash2}`;
|
|
15289
|
+
}
|
|
15290
|
+
function isValidDigest(digest) {
|
|
15291
|
+
return /^sha256:[a-f0-9]{64}$/.test(digest);
|
|
15292
|
+
}
|
|
15293
|
+
|
|
15281
15294
|
// src/registry/registries/CASRegistry.ts
|
|
15282
15295
|
class CASRegistry {
|
|
15283
15296
|
rxaStore;
|
|
@@ -15320,7 +15333,9 @@ class CASRegistry {
|
|
|
15320
15333
|
keywords: storedRxm.keywords,
|
|
15321
15334
|
repository: storedRxm.repository
|
|
15322
15335
|
},
|
|
15323
|
-
archive: {
|
|
15336
|
+
archive: {
|
|
15337
|
+
digest: storedRxm.digest ?? computeArchiveDigest(storedRxm.files)
|
|
15338
|
+
},
|
|
15324
15339
|
source: {}
|
|
15325
15340
|
};
|
|
15326
15341
|
const rxa = await archive(files);
|
|
@@ -15330,9 +15345,10 @@ class CASRegistry {
|
|
|
15330
15345
|
const files = await extract(rxr.archive);
|
|
15331
15346
|
const fileDigests = {};
|
|
15332
15347
|
for (const [filename, content] of Object.entries(files)) {
|
|
15333
|
-
const
|
|
15334
|
-
fileDigests[filename] =
|
|
15348
|
+
const digest2 = await this.rxaStore.put(content);
|
|
15349
|
+
fileDigests[filename] = digest2;
|
|
15335
15350
|
}
|
|
15351
|
+
const digest = computeArchiveDigest(fileDigests);
|
|
15336
15352
|
const storedRxm = {
|
|
15337
15353
|
registry: rxr.manifest.definition.registry,
|
|
15338
15354
|
path: rxr.manifest.definition.path,
|
|
@@ -15344,12 +15360,18 @@ class CASRegistry {
|
|
|
15344
15360
|
license: rxr.manifest.definition.license,
|
|
15345
15361
|
keywords: rxr.manifest.definition.keywords,
|
|
15346
15362
|
repository: rxr.manifest.definition.repository,
|
|
15363
|
+
digest,
|
|
15347
15364
|
files: fileDigests,
|
|
15348
15365
|
createdAt: new Date,
|
|
15349
15366
|
updatedAt: new Date
|
|
15350
15367
|
};
|
|
15351
15368
|
await this.rxmStore.put(storedRxm);
|
|
15352
15369
|
await this.rxmStore.setLatest(rxr.manifest.definition.name, rxr.manifest.definition.tag, rxr.manifest.definition.registry);
|
|
15370
|
+
return {
|
|
15371
|
+
definition: rxr.manifest.definition,
|
|
15372
|
+
archive: { digest },
|
|
15373
|
+
source: rxr.manifest.source
|
|
15374
|
+
};
|
|
15353
15375
|
}
|
|
15354
15376
|
async has(rxi) {
|
|
15355
15377
|
const tag = await this.resolveTag(rxi.name, rxi.tag ?? "latest", rxi.registry);
|
|
@@ -15548,15 +15570,6 @@ class LinkedRegistry {
|
|
|
15548
15570
|
}
|
|
15549
15571
|
}
|
|
15550
15572
|
}
|
|
15551
|
-
// src/registry/store/digest.ts
|
|
15552
|
-
import { createHash } from "node:crypto";
|
|
15553
|
-
function computeDigest(data) {
|
|
15554
|
-
const hash2 = createHash("sha256").update(data).digest("hex");
|
|
15555
|
-
return `sha256:${hash2}`;
|
|
15556
|
-
}
|
|
15557
|
-
function isValidDigest(digest) {
|
|
15558
|
-
return /^sha256:[a-f0-9]{64}$/.test(digest);
|
|
15559
|
-
}
|
|
15560
15573
|
// src/registry/store/MemoryRXAStore.ts
|
|
15561
15574
|
class MemoryRXAStore {
|
|
15562
15575
|
blobs = new Map;
|
|
@@ -15760,7 +15773,47 @@ var skill_type_default = {
|
|
|
15760
15773
|
}
|
|
15761
15774
|
}
|
|
15762
15775
|
};
|
|
15763
|
-
var
|
|
15776
|
+
var prototypeType = {
|
|
15777
|
+
name: "prototype",
|
|
15778
|
+
description: "Instruction set for materializing roles and organizations",
|
|
15779
|
+
code: `// @resolver: prototype_type_default
|
|
15780
|
+
var prototype_type_default = {
|
|
15781
|
+
async resolve(ctx) {
|
|
15782
|
+
var protoFile = ctx.files["prototype.json"];
|
|
15783
|
+
if (!protoFile) throw new Error("Prototype resource must contain a prototype.json file");
|
|
15784
|
+
var decoder = new TextDecoder();
|
|
15785
|
+
var instructions = JSON.parse(decoder.decode(protoFile));
|
|
15786
|
+
if (!Array.isArray(instructions)) {
|
|
15787
|
+
throw new Error("prototype.json must be a JSON array of instructions");
|
|
15788
|
+
}
|
|
15789
|
+
var resolved = instructions.map(function(instr) {
|
|
15790
|
+
var resolvedArgs = {};
|
|
15791
|
+
var keys = Object.keys(instr.args || {});
|
|
15792
|
+
for (var i = 0; i < keys.length; i++) {
|
|
15793
|
+
var key = keys[i];
|
|
15794
|
+
var value = instr.args[key];
|
|
15795
|
+
if (typeof value === "string" && value.startsWith("@")) {
|
|
15796
|
+
var filename = value.slice(1);
|
|
15797
|
+
var file = ctx.files[filename];
|
|
15798
|
+
if (!file) throw new Error("Referenced file not found: " + filename);
|
|
15799
|
+
resolvedArgs[key] = decoder.decode(file);
|
|
15800
|
+
} else {
|
|
15801
|
+
resolvedArgs[key] = value;
|
|
15802
|
+
}
|
|
15803
|
+
}
|
|
15804
|
+
return { op: instr.op, args: resolvedArgs };
|
|
15805
|
+
});
|
|
15806
|
+
return { id: ctx.manifest.name, instructions: resolved };
|
|
15807
|
+
}
|
|
15808
|
+
};`
|
|
15809
|
+
};
|
|
15810
|
+
var builtinTypes = [
|
|
15811
|
+
textType,
|
|
15812
|
+
jsonType,
|
|
15813
|
+
binaryType,
|
|
15814
|
+
skillType,
|
|
15815
|
+
prototypeType
|
|
15816
|
+
];
|
|
15764
15817
|
// src/type/bundler.ts
|
|
15765
15818
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
15766
15819
|
import { isAbsolute, resolve } from "node:path";
|
|
@@ -15863,8 +15916,10 @@ export {
|
|
|
15863
15916
|
wrap,
|
|
15864
15917
|
withDomainValidation,
|
|
15865
15918
|
textType,
|
|
15919
|
+
skillType,
|
|
15866
15920
|
resource,
|
|
15867
15921
|
resolveSource,
|
|
15922
|
+
prototypeType,
|
|
15868
15923
|
parse5 as parse,
|
|
15869
15924
|
manifest,
|
|
15870
15925
|
locate,
|
|
@@ -15890,6 +15945,7 @@ export {
|
|
|
15890
15945
|
ResourceJsonDetector,
|
|
15891
15946
|
RegistryMiddleware,
|
|
15892
15947
|
RegistryError,
|
|
15948
|
+
PrototypeDetector,
|
|
15893
15949
|
MemoryRXMStore,
|
|
15894
15950
|
MemoryRXAStore,
|
|
15895
15951
|
ManifestError,
|
|
@@ -15904,4 +15960,4 @@ export {
|
|
|
15904
15960
|
CASRegistry
|
|
15905
15961
|
};
|
|
15906
15962
|
|
|
15907
|
-
//# debugId=
|
|
15963
|
+
//# debugId=0BF8A796080AFBD664756E2164756E21
|