@telorun/kernel 0.4.1 → 0.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 (60) hide show
  1. package/dist/controller-loader.d.ts +19 -20
  2. package/dist/controller-loader.d.ts.map +1 -1
  3. package/dist/controller-loader.js +67 -247
  4. package/dist/controller-loader.js.map +1 -1
  5. package/dist/controller-loaders/napi-loader.d.ts +27 -0
  6. package/dist/controller-loaders/napi-loader.d.ts.map +1 -0
  7. package/dist/controller-loaders/napi-loader.js +158 -0
  8. package/dist/controller-loaders/napi-loader.js.map +1 -0
  9. package/dist/controller-loaders/npm-loader.d.ts +20 -0
  10. package/dist/controller-loaders/npm-loader.d.ts.map +1 -0
  11. package/dist/controller-loaders/npm-loader.js +256 -0
  12. package/dist/controller-loaders/npm-loader.js.map +1 -0
  13. package/dist/controller-registry.d.ts +30 -20
  14. package/dist/controller-registry.d.ts.map +1 -1
  15. package/dist/controller-registry.js +50 -99
  16. package/dist/controller-registry.js.map +1 -1
  17. package/dist/controllers/module/import-controller.d.ts +11 -0
  18. package/dist/controllers/module/import-controller.d.ts.map +1 -1
  19. package/dist/controllers/module/import-controller.js +28 -1
  20. package/dist/controllers/module/import-controller.js.map +1 -1
  21. package/dist/controllers/resource-definition/abstract-controller.d.ts +35 -0
  22. package/dist/controllers/resource-definition/abstract-controller.d.ts.map +1 -0
  23. package/dist/controllers/resource-definition/abstract-controller.js +34 -0
  24. package/dist/controllers/resource-definition/abstract-controller.js.map +1 -0
  25. package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
  26. package/dist/controllers/resource-definition/resource-definition-controller.js +1 -1
  27. package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
  28. package/dist/kernel.d.ts +1 -1
  29. package/dist/kernel.d.ts.map +1 -1
  30. package/dist/kernel.js +35 -14
  31. package/dist/kernel.js.map +1 -1
  32. package/dist/manifest-schemas.d.ts +50 -0
  33. package/dist/manifest-schemas.d.ts.map +1 -1
  34. package/dist/manifest-schemas.js +31 -0
  35. package/dist/manifest-schemas.js.map +1 -1
  36. package/dist/module-context.d.ts +11 -1
  37. package/dist/module-context.d.ts.map +1 -1
  38. package/dist/module-context.js +6 -0
  39. package/dist/module-context.js.map +1 -1
  40. package/dist/resource-context.d.ts +2 -1
  41. package/dist/resource-context.d.ts.map +1 -1
  42. package/dist/resource-context.js +6 -1
  43. package/dist/resource-context.js.map +1 -1
  44. package/dist/runtime-registry.d.ts +50 -0
  45. package/dist/runtime-registry.d.ts.map +1 -0
  46. package/dist/runtime-registry.js +140 -0
  47. package/dist/runtime-registry.js.map +1 -0
  48. package/package.json +3 -3
  49. package/src/controller-loader.ts +77 -273
  50. package/src/controller-loaders/napi-loader.ts +191 -0
  51. package/src/controller-loaders/npm-loader.ts +285 -0
  52. package/src/controller-registry.ts +66 -129
  53. package/src/controllers/module/import-controller.ts +30 -1
  54. package/src/controllers/resource-definition/abstract-controller.ts +56 -0
  55. package/src/controllers/resource-definition/resource-definition-controller.ts +1 -0
  56. package/src/kernel.ts +43 -13
  57. package/src/manifest-schemas.ts +33 -0
  58. package/src/module-context.ts +22 -1
  59. package/src/resource-context.ts +8 -1
  60. package/src/runtime-registry.ts +170 -0
@@ -0,0 +1,256 @@
1
+ import { execFile } from "child_process";
2
+ import { createHash } from "crypto";
3
+ import * as fs from "fs/promises";
4
+ import * as os from "os";
5
+ import { PackageURL } from "packageurl-js";
6
+ import * as path from "path";
7
+ import { promisify } from "util";
8
+ const homedir = os.homedir();
9
+ const cacheRoot = process.env.TELO_CACHE_DIR
10
+ ? path.resolve(process.env.TELO_CACHE_DIR)
11
+ : path.join(homedir, ".cache", "telo");
12
+ const npmCacheRoot = path.join(cacheRoot, "npm");
13
+ const isBun = typeof globalThis.Bun !== "undefined";
14
+ export class NpmControllerLoader {
15
+ /**
16
+ * Resolve a `pkg:npm/...` PURL to a controller module instance. Tries, in order:
17
+ * a relative `local_path` qualifier, the workspace's `node_modules`, and finally
18
+ * an isolated install under `~/.cache/telo/npm/<hash>`.
19
+ */
20
+ async load(purl, baseUri) {
21
+ const [, namespace, name, versionSpec, qualifiers, entry] = PackageURL.parseString(purl);
22
+ const localPath = qualifiers?.get("local_path");
23
+ const cacheKey = createHash("sha256").update(purl).digest("hex").slice(0, 12);
24
+ const installDir = path.join(npmCacheRoot, cacheKey);
25
+ let packageRoot;
26
+ const isLocalManifest = baseUri && !baseUri.startsWith("http://") && !baseUri.startsWith("https://");
27
+ if (localPath && isLocalManifest) {
28
+ const baseUriPath = baseUri.startsWith("file://") ? baseUri.slice("file://".length) : baseUri;
29
+ const manifestDir = path.dirname(baseUriPath);
30
+ const resolvedLocalPath = path.resolve(manifestDir, localPath);
31
+ if (await this.pathExists(resolvedLocalPath)) {
32
+ packageRoot = resolvedLocalPath;
33
+ }
34
+ else {
35
+ const nodeModulesPath = await this.findInNodeModules(`${namespace}/${name}`);
36
+ if (nodeModulesPath) {
37
+ packageRoot = nodeModulesPath;
38
+ }
39
+ else {
40
+ await this.ensureNpmPackageInstalled(installDir, `${namespace}/${name}@${versionSpec}`);
41
+ packageRoot = this.getInstalledPackageRoot(installDir, `${namespace}/${name}`);
42
+ }
43
+ }
44
+ }
45
+ else {
46
+ const nodeModulesPath = await this.findInNodeModules(`${namespace}/${name}`);
47
+ if (nodeModulesPath) {
48
+ packageRoot = nodeModulesPath;
49
+ }
50
+ else {
51
+ await this.ensureNpmPackageInstalled(installDir, `${namespace}/${name}@${versionSpec}`);
52
+ packageRoot = this.getInstalledPackageRoot(installDir, `${namespace}/${name}`);
53
+ }
54
+ }
55
+ const entryFile = await this.resolvePackageEntry(packageRoot, entry ? `./${entry}` : ".");
56
+ const instance = await import(entryFile);
57
+ if (!instance || (!instance.create && !instance.register)) {
58
+ throw new Error(`Invalid controller loaded from "${purl}": missing create or register function`);
59
+ }
60
+ return instance;
61
+ }
62
+ async ensureNpmPackageInstalled(installDir, packageSpec) {
63
+ const packageName = this.getPackageName(packageSpec.startsWith(".") || path.isAbsolute(packageSpec)
64
+ ? await this.getLocalPackageName(packageSpec)
65
+ : packageSpec);
66
+ const packageRoot = this.getInstalledPackageRoot(installDir, packageName);
67
+ const packageJsonPath = path.join(packageRoot, "package.json");
68
+ if (await this.pathExists(packageJsonPath)) {
69
+ return;
70
+ }
71
+ await fs.mkdir(installDir, { recursive: true });
72
+ const rootPackageJson = path.join(installDir, "package.json");
73
+ if (!(await this.pathExists(rootPackageJson))) {
74
+ await fs.writeFile(rootPackageJson, JSON.stringify({ name: "telo-cache", private: true }, null, 2));
75
+ }
76
+ const execFileAsync = promisify(execFile);
77
+ const args = [
78
+ "install",
79
+ "--no-audit",
80
+ "--no-fund",
81
+ "--silent",
82
+ "--prefix",
83
+ installDir,
84
+ packageSpec,
85
+ ];
86
+ await execFileAsync("npm", args);
87
+ }
88
+ getPackageName(packageSpec) {
89
+ if (packageSpec.startsWith("@")) {
90
+ const lastAt = packageSpec.lastIndexOf("@");
91
+ return lastAt > 0 ? packageSpec.slice(0, lastAt) : packageSpec;
92
+ }
93
+ const [name] = packageSpec.split("@");
94
+ return name;
95
+ }
96
+ getInstalledPackageRoot(installDir, packageName) {
97
+ const nameParts = packageName.split("/");
98
+ return path.join(installDir, "node_modules", ...nameParts);
99
+ }
100
+ async getLocalPackageName(packagePath) {
101
+ const packageJsonPath = path.join(packagePath, "package.json");
102
+ if (!(await this.pathExists(packageJsonPath))) {
103
+ throw new Error(`Local package missing package.json: ${packagePath}`);
104
+ }
105
+ const content = await fs.readFile(packageJsonPath, "utf8");
106
+ const parsed = JSON.parse(content);
107
+ if (!parsed?.name) {
108
+ throw new Error(`Local package missing name in package.json: ${packagePath}`);
109
+ }
110
+ return parsed.name;
111
+ }
112
+ async resolvePackageEntry(packageRoot, entry, packageName) {
113
+ const packageJsonPath = path.join(packageRoot, "package.json");
114
+ let resolvedPackageName = packageName;
115
+ let packageJson = null;
116
+ if (!resolvedPackageName && (await this.pathExists(packageJsonPath))) {
117
+ const content = await fs.readFile(packageJsonPath, "utf8");
118
+ try {
119
+ packageJson = JSON.parse(content);
120
+ resolvedPackageName = packageJson?.name;
121
+ }
122
+ catch {
123
+ resolvedPackageName = packageName;
124
+ }
125
+ }
126
+ else if (await this.pathExists(packageJsonPath)) {
127
+ try {
128
+ packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
129
+ }
130
+ catch {
131
+ packageJson = null;
132
+ }
133
+ }
134
+ const entryValue = entry.trim();
135
+ const exportTarget = this.resolvePackageExportTarget(packageJson?.exports, entryValue);
136
+ if (exportTarget) {
137
+ const resolved = path.resolve(packageRoot, exportTarget);
138
+ if (await this.pathExists(resolved)) {
139
+ return this.resolveForRuntime(resolved, packageRoot);
140
+ }
141
+ if (!path.extname(resolved)) {
142
+ const withJs = `${resolved}.js`;
143
+ if (await this.pathExists(withJs)) {
144
+ return withJs;
145
+ }
146
+ }
147
+ }
148
+ if ((entryValue === "." || entryValue === "./") && packageJson) {
149
+ const mainFields = ["module", "main"];
150
+ for (const field of mainFields) {
151
+ const target = packageJson[field];
152
+ if (typeof target === "string") {
153
+ const resolved = path.resolve(packageRoot, target);
154
+ if (await this.pathExists(resolved)) {
155
+ return this.resolveForRuntime(resolved, packageRoot);
156
+ }
157
+ if (!path.extname(resolved)) {
158
+ const withJs = `${resolved}.js`;
159
+ if (await this.pathExists(withJs)) {
160
+ return withJs;
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ const directPath = path.resolve(packageRoot, entryValue);
167
+ if (await this.pathExists(directPath)) {
168
+ return this.resolveForRuntime(directPath, packageRoot);
169
+ }
170
+ if (!path.extname(directPath)) {
171
+ const withJs = `${directPath}.js`;
172
+ if (await this.pathExists(withJs)) {
173
+ return withJs;
174
+ }
175
+ }
176
+ throw new Error(`Controller entry "${entryValue}" could not be resolved in ${packageRoot}`);
177
+ }
178
+ resolvePackageExportTarget(exportsField, entry) {
179
+ if (!exportsField) {
180
+ return null;
181
+ }
182
+ const key = entry === "." || entry === "./" ? "." : entry;
183
+ const target = exportsField[key];
184
+ return this.resolveExportTargetValue(target);
185
+ }
186
+ resolveExportTargetValue(target) {
187
+ if (!target) {
188
+ return null;
189
+ }
190
+ if (typeof target === "string") {
191
+ return target;
192
+ }
193
+ if (Array.isArray(target)) {
194
+ for (const item of target) {
195
+ const resolved = this.resolveExportTargetValue(item);
196
+ if (resolved) {
197
+ return resolved;
198
+ }
199
+ }
200
+ return null;
201
+ }
202
+ if (typeof target === "object") {
203
+ const preferredKeys = isBun
204
+ ? ["bun", "import", "default", "require"]
205
+ : ["import", "default", "require"];
206
+ for (const key of preferredKeys) {
207
+ if (target[key]) {
208
+ const resolved = this.resolveExportTargetValue(target[key]);
209
+ if (resolved) {
210
+ return resolved;
211
+ }
212
+ }
213
+ }
214
+ }
215
+ return null;
216
+ }
217
+ async resolveForRuntime(resolvedPath, packageRoot) {
218
+ if (isBun || !resolvedPath.endsWith(".ts")) {
219
+ return resolvedPath;
220
+ }
221
+ const relative = path.relative(packageRoot, resolvedPath);
222
+ const distEquivalent = path.resolve(packageRoot, relative.replace(/^src\//, "dist/").replace(/\.ts$/, ".js"));
223
+ if (await this.pathExists(distEquivalent)) {
224
+ return distEquivalent;
225
+ }
226
+ const jsPath = resolvedPath.replace(/\.ts$/, ".js");
227
+ if (await this.pathExists(jsPath)) {
228
+ return jsPath;
229
+ }
230
+ return resolvedPath;
231
+ }
232
+ async findInNodeModules(packageName) {
233
+ const nameParts = packageName.split("/");
234
+ const candidates = [
235
+ path.join(process.cwd(), "node_modules", ...nameParts),
236
+ path.join(process.cwd(), "node_modules", ".pnpm", "node_modules", ...nameParts),
237
+ ];
238
+ for (const candidate of candidates) {
239
+ const packageJsonPath = path.join(candidate, "package.json");
240
+ if (await this.pathExists(packageJsonPath)) {
241
+ return candidate;
242
+ }
243
+ }
244
+ return null;
245
+ }
246
+ async pathExists(filePath) {
247
+ try {
248
+ await fs.access(filePath);
249
+ return true;
250
+ }
251
+ catch {
252
+ return false;
253
+ }
254
+ }
255
+ }
256
+ //# sourceMappingURL=npm-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-loader.js","sourceRoot":"","sources":["../../src/controller-loaders/npm-loader.ts"],"names":[],"mappings":"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"}
@@ -1,28 +1,41 @@
1
- import { ControllerInstance, ResourceDefinition, RuntimeResource } from "@telorun/sdk";
1
+ import { ControllerInstance, ResourceDefinition } from "@telorun/sdk";
2
2
  /**
3
3
  * ControllerRegistry: Manages controller loading and dispatch
4
- * Maps fully-qualified resource kinds to their controller implementations
4
+ * Maps fully-qualified resource kinds to their controller implementations.
5
+ *
6
+ * Controllers are keyed by `(kind, runtimeFingerprint)` so that two
7
+ * `Telo.Import`s of the same library with different `runtime:` selections
8
+ * each get their own cached controller instance — the first winner does not
9
+ * lock out the second. Definitions remain kind-only; only the loaded
10
+ * controller instance is policy-scoped.
5
11
  */
6
12
  export declare class ControllerRegistry {
7
13
  private controllersByKind;
8
14
  private definitionsByKind;
9
- private controllerLoaders;
10
15
  /**
11
16
  * Register a controller definition
12
17
  */
13
18
  registerDefinition(definition: ResourceDefinition): void;
14
19
  /**
15
- * Get a controller instance for a kind
16
- * Lazy-loads controller code on first access
17
- * Throws if controller not found
20
+ * Get a controller instance for a (kind, fingerprint) pair. Lookup order:
21
+ * 1. Exact match for the requested fingerprint (the common path).
22
+ * 2. The "default" fingerprint kernel built-ins register here once and
23
+ * should be reachable from any module's fingerprinted lookup.
24
+ * 3. The first registered entry for this kind, regardless of fingerprint
25
+ * — handles the case of a root-context resource referencing a kind
26
+ * that an import loaded under its own runtime selection.
27
+ *
28
+ * Throws `ERR_CONTROLLER_NOT_LOADED` on full miss.
18
29
  */
19
- getController(kind: string): ControllerInstance;
30
+ getController(kind: string, fingerprint?: string): ControllerInstance;
20
31
  /**
21
- * Safe get - returns undefined if controller not found
32
+ * Safe get - returns undefined if controller not found. Same fallback
33
+ * order as `getController`.
22
34
  */
23
- getControllerOrUndefined(kind: string): ControllerInstance | undefined;
35
+ getControllerOrUndefined(kind: string, fingerprint?: string): ControllerInstance | undefined;
36
+ private lookup;
24
37
  /**
25
- * Check if a controller exists for this kind (definition or directly registered)
38
+ * Check if any controller exists for this kind (any fingerprint, or just a definition).
26
39
  */
27
40
  hasController(kind: string): boolean;
28
41
  /**
@@ -33,19 +46,16 @@ export declare class ControllerRegistry {
33
46
  * Get all registered kinds
34
47
  */
35
48
  getKinds(): string[];
36
- getControllerKinds(): string[];
37
- /**
38
- * Create a resource instance using its controller
39
- */
40
- create(kind: string, resource: RuntimeResource, ctx: any): Promise<any | null>;
41
49
  /**
42
- * Register a controller for a kind
50
+ * Distinct kinds with at least one registered controller. Used by the boot
51
+ * register-hook loop, which fires once per kind regardless of fingerprint.
43
52
  */
44
- registerController(kind: string, controller: ControllerInstance): void;
53
+ getControllerKinds(): string[];
45
54
  /**
46
- * Private: Register controller loader
55
+ * Register a controller for a (kind, fingerprint). Multiple registrations
56
+ * for the same kind with different fingerprints coexist; same fingerprint
57
+ * overwrites the prior entry.
47
58
  */
48
- private registerControllerLoader;
49
- private isModuleClass;
59
+ registerController(kind: string, controller: ControllerInstance, fingerprint?: string): void;
50
60
  }
51
61
  //# sourceMappingURL=controller-registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller-registry.d.ts","sourceRoot":"","sources":["../src/controller-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGvF;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAA8C;IACvE,OAAO,CAAC,iBAAiB,CAA8C;IACvE,OAAO,CAAC,iBAAiB,CAA6D;IACtF;;OAEG;IACH,kBAAkB,CAChB,UAAU,EAAE,kBAAkB,GAG7B,IAAI;IAgBP;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAmB/C;;OAEG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAQtE;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI3D;;OAEG;IACH,QAAQ,IAAI,MAAM,EAAE;IAIpB,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAQpF;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI;IAetE;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA2DhC,OAAO,CAAC,aAAa;CAKtB"}
1
+ {"version":3,"file":"controller-registry.d.ts","sourceRoot":"","sources":["../src/controller-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAgB,MAAM,cAAc,CAAC;AAIpF;;;;;;;;;GASG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAA2D;IACpF,OAAO,CAAC,iBAAiB,CAA8C;IAEvE;;OAEG;IACH,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI;IAOxD;;;;;;;;;;OAUG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,GAAE,MAA4B,GAAG,kBAAkB;IAW1F;;;OAGG;IACH,wBAAwB,CACtB,IAAI,EAAE,MAAM,EACZ,WAAW,GAAE,MAA4B,GACxC,kBAAkB,GAAG,SAAS;IAIjC,OAAO,CAAC,MAAM;IAUd;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIpC;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI3D;;OAEG;IACH,QAAQ,IAAI,MAAM,EAAE;IAIpB;;;OAGG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;;;OAIG;IACH,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,kBAAkB,EAC9B,WAAW,GAAE,MAA4B,GACxC,IAAI;CAkBR"}
@@ -1,64 +1,64 @@
1
- import * as path from "path";
1
+ import { RuntimeError } from "@telorun/sdk";
2
+ const DEFAULT_FINGERPRINT = "default";
2
3
  /**
3
4
  * ControllerRegistry: Manages controller loading and dispatch
4
- * Maps fully-qualified resource kinds to their controller implementations
5
+ * Maps fully-qualified resource kinds to their controller implementations.
6
+ *
7
+ * Controllers are keyed by `(kind, runtimeFingerprint)` so that two
8
+ * `Telo.Import`s of the same library with different `runtime:` selections
9
+ * each get their own cached controller instance — the first winner does not
10
+ * lock out the second. Definitions remain kind-only; only the loaded
11
+ * controller instance is policy-scoped.
5
12
  */
6
13
  export class ControllerRegistry {
7
14
  constructor() {
8
15
  this.controllersByKind = new Map();
9
16
  this.definitionsByKind = new Map();
10
- this.controllerLoaders = new Map();
11
17
  }
12
18
  /**
13
19
  * Register a controller definition
14
20
  */
15
21
  registerDefinition(definition) {
16
- // Construct fully qualified kind: Namespace.Name
17
- // Only add namespace if name is not already qualified (doesn't contain a dot)
18
22
  const namespace = definition.metadata.module;
19
- const baseDir = null;
20
23
  const name = definition.metadata.name;
21
24
  const kind = namespace && !name.includes(".") ? `${namespace}.${name}` : name;
22
25
  this.definitionsByKind.set(kind, definition);
23
- // If definition has controllers, register loader for them
24
- if (definition.controllers && definition.controllers.length > 0 && baseDir) {
25
- this.registerControllerLoader(kind, definition, baseDir);
26
- }
27
26
  }
28
27
  /**
29
- * Get a controller instance for a kind
30
- * Lazy-loads controller code on first access
31
- * Throws if controller not found
28
+ * Get a controller instance for a (kind, fingerprint) pair. Lookup order:
29
+ * 1. Exact match for the requested fingerprint (the common path).
30
+ * 2. The "default" fingerprint kernel built-ins register here once and
31
+ * should be reachable from any module's fingerprinted lookup.
32
+ * 3. The first registered entry for this kind, regardless of fingerprint
33
+ * — handles the case of a root-context resource referencing a kind
34
+ * that an import loaded under its own runtime selection.
35
+ *
36
+ * Throws `ERR_CONTROLLER_NOT_LOADED` on full miss.
32
37
  */
33
- getController(kind) {
34
- // Return cached instance if available
35
- if (this.controllersByKind.has(kind)) {
36
- return this.controllersByKind.get(kind);
38
+ getController(kind, fingerprint = DEFAULT_FINGERPRINT) {
39
+ const cached = this.lookup(kind, fingerprint);
40
+ if (cached) {
41
+ return cached;
37
42
  }
38
- // Load controller if loader is registered
39
- // const loader = this.controllerLoaders.get(kind);
40
- // if (loader) {
41
- // const controller = await loader();
42
- // this.controllersByKind.set(kind, controller);
43
- // return controller;
44
- // }
45
- return {
46
- schema: { type: "object", additionalProperties: false },
47
- };
48
- // throw new Error(`No controller registered for kind: ${kind}`);
43
+ throw new RuntimeError("ERR_CONTROLLER_NOT_LOADED", `No controller loaded for kind "${kind}" (runtime fingerprint "${fingerprint}"). The kind's Telo.Definition must init before its controller is consulted.`);
49
44
  }
50
45
  /**
51
- * Safe get - returns undefined if controller not found
46
+ * Safe get - returns undefined if controller not found. Same fallback
47
+ * order as `getController`.
52
48
  */
53
- getControllerOrUndefined(kind) {
54
- // Return cached instance if available
55
- if (this.controllersByKind.has(kind)) {
56
- return this.controllersByKind.get(kind);
57
- }
58
- return undefined;
49
+ getControllerOrUndefined(kind, fingerprint = DEFAULT_FINGERPRINT) {
50
+ return this.lookup(kind, fingerprint);
51
+ }
52
+ lookup(kind, fingerprint) {
53
+ const byFp = this.controllersByKind.get(kind);
54
+ if (!byFp)
55
+ return undefined;
56
+ return (byFp.get(fingerprint) ??
57
+ byFp.get(DEFAULT_FINGERPRINT) ??
58
+ byFp.values().next().value);
59
59
  }
60
60
  /**
61
- * Check if a controller exists for this kind (definition or directly registered)
61
+ * Check if any controller exists for this kind (any fingerprint, or just a definition).
62
62
  */
63
63
  hasController(kind) {
64
64
  return this.controllersByKind.has(kind) || this.definitionsByKind.has(kind);
@@ -75,27 +75,22 @@ export class ControllerRegistry {
75
75
  getKinds() {
76
76
  return Array.from(this.definitionsByKind.keys());
77
77
  }
78
- getControllerKinds() {
79
- return Array.from(this.controllersByKind.keys());
80
- }
81
78
  /**
82
- * Create a resource instance using its controller
79
+ * Distinct kinds with at least one registered controller. Used by the boot
80
+ * register-hook loop, which fires once per kind regardless of fingerprint.
83
81
  */
84
- async create(kind, resource, ctx) {
85
- const controller = this.getController(kind);
86
- if (!controller || !controller.create) {
87
- return null;
88
- }
89
- return controller.create(resource, ctx);
82
+ getControllerKinds() {
83
+ return Array.from(this.controllersByKind.keys());
90
84
  }
91
85
  /**
92
- * Register a controller for a kind
86
+ * Register a controller for a (kind, fingerprint). Multiple registrations
87
+ * for the same kind with different fingerprints coexist; same fingerprint
88
+ * overwrites the prior entry.
93
89
  */
94
- registerController(kind, controller) {
90
+ registerController(kind, controller, fingerprint = DEFAULT_FINGERPRINT) {
95
91
  if (!this.definitionsByKind.has(kind)) {
96
92
  throw new Error(`Cannot register controller for kind ${kind} without definition`);
97
93
  }
98
- // Ensure controller has schema from definition
99
94
  const definition = this.definitionsByKind.get(kind);
100
95
  const wrappedController = {
101
96
  ...controller,
@@ -103,56 +98,12 @@ export class ControllerRegistry {
103
98
  inputType: controller.inputType,
104
99
  outputType: controller.outputType,
105
100
  };
106
- this.controllersByKind.set(kind, wrappedController);
107
- }
108
- /**
109
- * Private: Register controller loader
110
- */
111
- registerControllerLoader(kind, definition, moduleDir) {
112
- const controllerDef = definition.controllers?.[0]; // Use first matching controller for now
113
- if (!controllerDef)
114
- return;
115
- this.controllerLoaders.set(kind, async () => {
116
- const modulePath = path.resolve(moduleDir, controllerDef.entry);
117
- const moduleRuntime = await import(modulePath);
118
- const exported = moduleRuntime.default || moduleRuntime.Module || moduleRuntime;
119
- const registerFn = typeof moduleRuntime.register === "function"
120
- ? moduleRuntime.register
121
- : typeof exported === "function" && !this.isModuleClass(exported)
122
- ? exported
123
- : null;
124
- const createFn = typeof moduleRuntime.create === "function"
125
- ? moduleRuntime.create
126
- : typeof exported?.create === "function"
127
- ? exported.create
128
- : null;
129
- const executeFn = typeof moduleRuntime.execute === "function"
130
- ? moduleRuntime.execute
131
- : typeof exported?.execute === "function"
132
- ? exported.execute
133
- : null;
134
- const compileFn = typeof moduleRuntime.compile === "function"
135
- ? moduleRuntime.compile
136
- : typeof exported?.compile === "function"
137
- ? exported.compile
138
- : null;
139
- if (!registerFn && !executeFn && !createFn && !compileFn) {
140
- throw new Error(`Controller for "${kind}" exports no usable handlers`);
141
- }
142
- if (!definition.schema) {
143
- throw new Error(`Definition for "${kind}" does not have schema`);
144
- }
145
- return {
146
- register: registerFn ?? undefined,
147
- create: createFn ?? undefined,
148
- execute: executeFn ?? undefined,
149
- compile: compileFn ?? undefined,
150
- schema: definition.schema,
151
- };
152
- });
153
- }
154
- isModuleClass(obj) {
155
- return (typeof obj === "function" && (obj.name === "Controller" || obj.toString().includes("class")));
101
+ let byFp = this.controllersByKind.get(kind);
102
+ if (!byFp) {
103
+ byFp = new Map();
104
+ this.controllersByKind.set(kind, byFp);
105
+ }
106
+ byFp.set(fingerprint, wrappedController);
156
107
  }
157
108
  }
158
109
  //# sourceMappingURL=controller-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller-registry.js","sourceRoot":"","sources":["../src/controller-registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IAA/B;QACU,sBAAiB,GAAoC,IAAI,GAAG,EAAE,CAAC;QAC/D,sBAAiB,GAAoC,IAAI,GAAG,EAAE,CAAC;QAC/D,sBAAiB,GAAmD,IAAI,GAAG,EAAE,CAAC;IAoLxF,CAAC;IAnLC;;OAEG;IACH,kBAAkB,CAChB,UAA8B;QAI9B,iDAAiD;QACjD,8EAA8E;QAC9E,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtC,MAAM,IAAI,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAE9E,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAE7C,0DAA0D;QAC1D,IAAI,UAAU,CAAC,WAAW,IAAI,UAAU,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;YAC3E,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,aAAa,CAAC,IAAY;QACxB,sCAAsC;QACtC,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QAC3C,CAAC;QAED,0CAA0C;QAC1C,mDAAmD;QACnD,gBAAgB;QAChB,uCAAuC;QACvC,kDAAkD;QAClD,uBAAuB;QACvB,IAAI;QACJ,OAAO;YACL,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,oBAAoB,EAAE,KAAK,EAAE;SACxD,CAAC;QACF,iEAAiE;IACnE,CAAC;IAED;;OAEG;IACH,wBAAwB,CAAC,IAAY;QACnC,sCAAsC;QACtC,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,kBAAkB;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,QAAyB,EAAE,GAAQ;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,kBAAkB,CAAC,IAAY,EAAE,UAA8B;QAC7D,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,qBAAqB,CAAC,CAAC;QACpF,CAAC;QACD,+CAA+C;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,iBAAiB,GAAuB;YAC5C,GAAG,UAAU;YACb,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,UAAU,EAAE,MAAM;YAC/C,SAAS,EAAE,UAAU,CAAC,SAAS;YAC/B,UAAU,EAAE,UAAU,CAAC,UAAU;SAClC,CAAC;QACF,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACK,wBAAwB,CAC9B,IAAY,EACZ,UAA8B,EAC9B,SAAiB;QAEjB,MAAM,aAAa,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,wCAAwC;QAC3F,IAAI,CAAC,aAAa;YAAE,OAAO;QAE3B,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;YAChE,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,MAAM,IAAI,aAAa,CAAC;YAEhF,MAAM,UAAU,GACd,OAAO,aAAa,CAAC,QAAQ,KAAK,UAAU;gBAC1C,CAAC,CAAC,aAAa,CAAC,QAAQ;gBACxB,CAAC,CAAC,OAAO,QAAQ,KAAK,UAAU,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;oBAC/D,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,IAAI,CAAC;YAEb,MAAM,QAAQ,GACZ,OAAO,aAAa,CAAC,MAAM,KAAK,UAAU;gBACxC,CAAC,CAAC,aAAa,CAAC,MAAM;gBACtB,CAAC,CAAC,OAAO,QAAQ,EAAE,MAAM,KAAK,UAAU;oBACtC,CAAC,CAAC,QAAQ,CAAC,MAAM;oBACjB,CAAC,CAAC,IAAI,CAAC;YAEb,MAAM,SAAS,GACb,OAAO,aAAa,CAAC,OAAO,KAAK,UAAU;gBACzC,CAAC,CAAC,aAAa,CAAC,OAAO;gBACvB,CAAC,CAAC,OAAO,QAAQ,EAAE,OAAO,KAAK,UAAU;oBACvC,CAAC,CAAC,QAAQ,CAAC,OAAO;oBAClB,CAAC,CAAC,IAAI,CAAC;YAEb,MAAM,SAAS,GACb,OAAO,aAAa,CAAC,OAAO,KAAK,UAAU;gBACzC,CAAC,CAAC,aAAa,CAAC,OAAO;gBACvB,CAAC,CAAC,OAAO,QAAQ,EAAE,OAAO,KAAK,UAAU;oBACvC,CAAC,CAAC,QAAQ,CAAC,OAAO;oBAClB,CAAC,CAAC,IAAI,CAAC;YAEb,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;gBACzD,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,8BAA8B,CAAC,CAAC;YACzE,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,wBAAwB,CAAC,CAAC;YACnE,CAAC;YAED,OAAO;gBACL,QAAQ,EAAE,UAAU,IAAI,SAAS;gBACjC,MAAM,EAAE,QAAQ,IAAI,SAAS;gBAC7B,OAAO,EAAE,SAAS,IAAI,SAAS;gBAC/B,OAAO,EAAE,SAAS,IAAI,SAAS;gBAC/B,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,GAAQ;QAC5B,OAAO,CACL,OAAO,GAAG,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAC7F,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"controller-registry.js","sourceRoot":"","sources":["../src/controller-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,YAAY,EAAE,MAAM,cAAc,CAAC;AAEpF,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAEtC;;;;;;;;;GASG;AACH,MAAM,OAAO,kBAAkB;IAA/B;QACU,sBAAiB,GAAiD,IAAI,GAAG,EAAE,CAAC;QAC5E,sBAAiB,GAAoC,IAAI,GAAG,EAAE,CAAC;IA+GzE,CAAC;IA7GC;;OAEG;IACH,kBAAkB,CAAC,UAA8B;QAC/C,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtC,MAAM,IAAI,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9E,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;;;;OAUG;IACH,aAAa,CAAC,IAAY,EAAE,cAAsB,mBAAmB;QACnE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,YAAY,CACpB,2BAA2B,EAC3B,kCAAkC,IAAI,2BAA2B,WAAW,8EAA8E,CAC3J,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,wBAAwB,CACtB,IAAY,EACZ,cAAsB,mBAAmB;QAEzC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACxC,CAAC;IAEO,MAAM,CAAC,IAAY,EAAE,WAAmB;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAC5B,OAAO,CACL,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC;YAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAC3B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED;;;OAGG;IACH,kBAAkB;QAChB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAChB,IAAY,EACZ,UAA8B,EAC9B,cAAsB,mBAAmB;QAEzC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,qBAAqB,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,iBAAiB,GAAuB;YAC5C,GAAG,UAAU;YACb,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,UAAU,EAAE,MAAM;YAC/C,SAAS,EAAE,UAAU,CAAC,SAAS;YAC/B,UAAU,EAAE,UAAU,CAAC,UAAU;SAClC,CAAC;QACF,IAAI,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -28,6 +28,17 @@ export declare const schema: {
28
28
  secrets: {
29
29
  type: string;
30
30
  };
31
+ runtime: {
32
+ oneOf: ({
33
+ type: string;
34
+ items?: undefined;
35
+ } | {
36
+ type: string;
37
+ items: {
38
+ type: string;
39
+ };
40
+ })[];
41
+ };
31
42
  };
32
43
  required: string[];
33
44
  additionalProperties: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"import-controller.d.ts","sourceRoot":"","sources":["../../../src/controllers/module/import-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAoBtE,wBAAsB,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuG3F;AAeD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmBlB,CAAC"}
1
+ {"version":3,"file":"import-controller.d.ts","sourceRoot":"","sources":["../../../src/controllers/module/import-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAqBtE,wBAAsB,MAAM,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA6H3F;AAeD,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBlB,CAAC"}