@smthrs/plugin 0.0.0-stage → 1.0.0-rc.13
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/CHANGELOG.md +79 -0
- package/LICENSE +21 -0
- package/README.md +88 -2
- package/dist/cjs/Config.d.ts +129 -0
- package/dist/cjs/Config.d.ts.map +1 -0
- package/dist/cjs/Config.js +115 -0
- package/dist/cjs/Config.js.map +7 -0
- package/dist/cjs/Hooks.d.ts +176 -0
- package/dist/cjs/Hooks.d.ts.map +1 -0
- package/dist/cjs/Hooks.js +34 -0
- package/dist/cjs/Hooks.js.map +7 -0
- package/dist/cjs/Kernel.d.ts +81 -0
- package/dist/cjs/Kernel.d.ts.map +1 -0
- package/dist/cjs/Kernel.js +57 -0
- package/dist/cjs/Kernel.js.map +7 -0
- package/dist/cjs/Plugin.d.ts +71 -0
- package/dist/cjs/Plugin.d.ts.map +1 -0
- package/dist/cjs/Plugin.js +25 -0
- package/dist/cjs/Plugin.js.map +7 -0
- package/dist/cjs/PluginError.d.ts +50 -0
- package/dist/cjs/PluginError.d.ts.map +1 -0
- package/dist/cjs/PluginError.js +58 -0
- package/dist/cjs/PluginError.js.map +7 -0
- package/dist/cjs/Plugins.d.ts +97 -0
- package/dist/cjs/Plugins.d.ts.map +1 -0
- package/dist/cjs/Plugins.js +169 -0
- package/dist/cjs/Plugins.js.map +7 -0
- package/dist/cjs/Resolve.d.ts +128 -0
- package/dist/cjs/Resolve.d.ts.map +1 -0
- package/dist/cjs/Resolve.js +346 -0
- package/dist/cjs/Resolve.js.map +7 -0
- package/dist/cjs/index.d.ts +83 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/Boundary.d.ts +96 -0
- package/dist/cjs/internal/Boundary.d.ts.map +1 -0
- package/dist/cjs/internal/Boundary.js +129 -0
- package/dist/cjs/internal/Boundary.js.map +7 -0
- package/dist/cjs/internal/mergePluginLayers.d.ts +21 -0
- package/dist/cjs/internal/mergePluginLayers.d.ts.map +1 -0
- package/dist/cjs/internal/mergePluginLayers.js +57 -0
- package/dist/cjs/internal/mergePluginLayers.js.map +7 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.d.ts +23 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.d.ts.map +1 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.js +92 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/Config.d.ts +129 -0
- package/dist/esm/Config.d.ts.map +1 -0
- package/dist/esm/Config.js +160 -0
- package/dist/esm/Config.js.map +1 -0
- package/dist/esm/Hooks.d.ts +176 -0
- package/dist/esm/Hooks.d.ts.map +1 -0
- package/dist/esm/Hooks.js +56 -0
- package/dist/esm/Hooks.js.map +1 -0
- package/dist/esm/Kernel.d.ts +81 -0
- package/dist/esm/Kernel.d.ts.map +1 -0
- package/dist/esm/Kernel.js +58 -0
- package/dist/esm/Kernel.js.map +1 -0
- package/dist/esm/Plugin.d.ts +71 -0
- package/dist/esm/Plugin.d.ts.map +1 -0
- package/dist/esm/Plugin.js +20 -0
- package/dist/esm/Plugin.js.map +1 -0
- package/dist/esm/PluginError.d.ts +50 -0
- package/dist/esm/PluginError.d.ts.map +1 -0
- package/dist/esm/PluginError.js +53 -0
- package/dist/esm/PluginError.js.map +1 -0
- package/dist/esm/Plugins.d.ts +97 -0
- package/dist/esm/Plugins.d.ts.map +1 -0
- package/dist/esm/Plugins.js +190 -0
- package/dist/esm/Plugins.js.map +1 -0
- package/dist/esm/Resolve.d.ts +128 -0
- package/dist/esm/Resolve.d.ts.map +1 -0
- package/dist/esm/Resolve.js +369 -0
- package/dist/esm/Resolve.js.map +1 -0
- package/dist/esm/index.d.ts +83 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +48 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/Boundary.d.ts +96 -0
- package/dist/esm/internal/Boundary.d.ts.map +1 -0
- package/dist/esm/internal/Boundary.js +162 -0
- package/dist/esm/internal/Boundary.js.map +1 -0
- package/dist/esm/internal/mergePluginLayers.d.ts +21 -0
- package/dist/esm/internal/mergePluginLayers.d.ts.map +1 -0
- package/dist/esm/internal/mergePluginLayers.js +41 -0
- package/dist/esm/internal/mergePluginLayers.js.map +1 -0
- package/dist/esm/internal/snapshotCacheEnvironment.d.ts +23 -0
- package/dist/esm/internal/snapshotCacheEnvironment.d.ts.map +1 -0
- package/dist/esm/internal/snapshotCacheEnvironment.js +64 -0
- package/dist/esm/internal/snapshotCacheEnvironment.js.map +1 -0
- package/docs/README.md +133 -0
- package/docs/api.md +524 -0
- package/docs/concepts/configuration.md +111 -0
- package/docs/concepts/hook-kinds.md +107 -0
- package/docs/concepts/resolution.md +132 -0
- package/docs/guides/cache-identity.md +106 -0
- package/docs/guides/contribute-services.md +84 -0
- package/docs/guides/host-your-own-hooks.md +129 -0
- package/docs/guides/order-handlers.md +76 -0
- package/docs/guides/select-plugins.md +72 -0
- package/docs/guides/testing.md +149 -0
- package/docs/installation.md +75 -0
- package/docs/quickstart.md +152 -0
- package/docs/troubleshooting.md +180 -0
- package/package.json +179 -3
- package/src/Config.ts +207 -0
- package/src/Hooks.ts +212 -0
- package/src/Kernel.ts +119 -0
- package/src/Plugin.ts +80 -0
- package/src/PluginError.ts +62 -0
- package/src/Plugins.ts +271 -0
- package/src/Resolve.ts +539 -0
- package/src/index.ts +91 -0
- package/src/internal/Boundary.ts +252 -0
- package/src/internal/mergePluginLayers.ts +57 -0
- package/src/internal/snapshotCacheEnvironment.ts +78 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inert JSON admission for plugin configuration and cache identity.
|
|
3
|
+
*
|
|
4
|
+
* Reflection is descriptor-only: accessors never execute, hostile proxies are
|
|
5
|
+
* refused, and accepted values are detached before they are frozen.
|
|
6
|
+
*
|
|
7
|
+
* @private
|
|
8
|
+
* @since 1.0.0-rc.0
|
|
9
|
+
*/
|
|
10
|
+
import * as BoundedJson from "@smthrs/canonical/BoundedJson";
|
|
11
|
+
/**
|
|
12
|
+
* Strict JSON value accepted by the boundary.
|
|
13
|
+
*
|
|
14
|
+
* @private
|
|
15
|
+
* @since 1.0.0-rc.0
|
|
16
|
+
*/
|
|
17
|
+
export type Json = BoundedJson.Json;
|
|
18
|
+
/**
|
|
19
|
+
* Resource bounds for one admitted tree.
|
|
20
|
+
*
|
|
21
|
+
* @private
|
|
22
|
+
* @since 1.0.0-rc.0
|
|
23
|
+
*/
|
|
24
|
+
export type Limits = BoundedJson.StrictLimits;
|
|
25
|
+
/**
|
|
26
|
+
* Successful admission.
|
|
27
|
+
*
|
|
28
|
+
* @private
|
|
29
|
+
* @since 1.0.0-rc.0
|
|
30
|
+
*/
|
|
31
|
+
export interface AdmissionSuccess {
|
|
32
|
+
readonly ok: true;
|
|
33
|
+
readonly value: Json;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Refusal with a stable value path.
|
|
37
|
+
*
|
|
38
|
+
* @private
|
|
39
|
+
* @since 1.0.0-rc.0
|
|
40
|
+
*/
|
|
41
|
+
export interface AdmissionFailure {
|
|
42
|
+
readonly ok: false;
|
|
43
|
+
readonly path: string;
|
|
44
|
+
readonly complaint: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Result of inert JSON admission.
|
|
48
|
+
*
|
|
49
|
+
* @private
|
|
50
|
+
* @since 1.0.0-rc.0
|
|
51
|
+
*/
|
|
52
|
+
export type Admission = AdmissionSuccess | AdmissionFailure;
|
|
53
|
+
/**
|
|
54
|
+
* Default configuration bounds.
|
|
55
|
+
*
|
|
56
|
+
* @private
|
|
57
|
+
* @since 1.0.0-rc.0
|
|
58
|
+
*/
|
|
59
|
+
export declare const defaultLimits: Limits;
|
|
60
|
+
/**
|
|
61
|
+
* Tests whether a string contains paired UTF-16 surrogate units.
|
|
62
|
+
*
|
|
63
|
+
* @private
|
|
64
|
+
* @since 1.0.0-rc.0
|
|
65
|
+
*/
|
|
66
|
+
export declare const isWellFormedText: (value: string) => boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Copies one strict JSON tree under explicit resource bounds.
|
|
69
|
+
*
|
|
70
|
+
* @private
|
|
71
|
+
* @since 1.0.0-rc.0
|
|
72
|
+
*/
|
|
73
|
+
export declare const admit: (input: unknown, limits?: Limits) => Admission;
|
|
74
|
+
/**
|
|
75
|
+
* Admits only a JSON record at the root.
|
|
76
|
+
*
|
|
77
|
+
* @private
|
|
78
|
+
* @since 1.0.0-rc.0
|
|
79
|
+
*/
|
|
80
|
+
export declare const record: (input: unknown, limits?: Limits) => AdmissionSuccess | AdmissionFailure;
|
|
81
|
+
/**
|
|
82
|
+
* Merges two independently admitted records, retaining unchanged subtrees.
|
|
83
|
+
* Both operands must come from successful admission, and the patch must be a
|
|
84
|
+
* fresh copy: their trees must be disjoint. Each output branch then comes from
|
|
85
|
+
* at most one location in either tree, preserving the no-repeated-reference
|
|
86
|
+
* invariant without walking retained subtrees. Limits apply to the result.
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
* @since 1.0.0-rc.0
|
|
90
|
+
*/
|
|
91
|
+
export declare const mergeRecords: (base: {
|
|
92
|
+
readonly [key: string]: Json;
|
|
93
|
+
}, patch: {
|
|
94
|
+
readonly [key: string]: Json;
|
|
95
|
+
}, limits?: Limits) => Admission;
|
|
96
|
+
//# sourceMappingURL=Boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Boundary.d.ts","sourceRoot":"","sources":["../../../src/internal/Boundary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,WAAW,MAAM,+BAA+B,CAAA;AAE5D;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;AAEnC;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC,YAAY,CAAA;AAE7C;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;IACjB,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,gBAAgB,CAAA;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,MAO1B,CAAA;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,OAA+B,CAAA;AA4EhF;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,OAAO,EAAE,SAAQ,MAAsB,KAAG,SAatE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,MAAM,GACjB,OAAO,OAAO,EACd,SAAQ,MAAsB,KAC7B,gBAAgB,GAAG,gBAKrB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACtC,OAAO;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACvC,SAAQ,MAAsB,KAC7B,SA4CF,CAAA"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var Boundary_exports = {};
|
|
30
|
+
__export(Boundary_exports, {
|
|
31
|
+
admit: () => admit,
|
|
32
|
+
defaultLimits: () => defaultLimits,
|
|
33
|
+
isWellFormedText: () => isWellFormedText,
|
|
34
|
+
mergeRecords: () => mergeRecords,
|
|
35
|
+
record: () => record
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(Boundary_exports);
|
|
38
|
+
var BoundedJson = __toESM(require("@smthrs/canonical/BoundedJson"), 1);
|
|
39
|
+
const defaultLimits = Object.freeze({
|
|
40
|
+
maxBytes: 1024 * 1024,
|
|
41
|
+
maxDepth: 64,
|
|
42
|
+
maxMembers: 4096,
|
|
43
|
+
maxNodes: 8192,
|
|
44
|
+
maxStringBytes: 64 * 1024,
|
|
45
|
+
maxKeyBytes: 1024
|
|
46
|
+
});
|
|
47
|
+
const isWellFormedText = (value) => value.isWellFormed();
|
|
48
|
+
const childPath = (path, key) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
|
|
49
|
+
const encodedStringBytes = (value) => BoundedJson.encodedStringBytes(value);
|
|
50
|
+
const boundedPath = (path) => {
|
|
51
|
+
let bytes = 2 + 3;
|
|
52
|
+
let prefix = "";
|
|
53
|
+
for (const character of path) {
|
|
54
|
+
const point = character.codePointAt(0);
|
|
55
|
+
bytes += character === '"' || character === "\\" ? 2 : point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
|
|
56
|
+
if (bytes > 192) return `${prefix}...`;
|
|
57
|
+
prefix += character;
|
|
58
|
+
}
|
|
59
|
+
return path;
|
|
60
|
+
};
|
|
61
|
+
const snapshots = /* @__PURE__ */ new WeakMap();
|
|
62
|
+
const scalarTotals = (bytes) => ({ bytes, members: 0, nodes: 1, depth: 0 });
|
|
63
|
+
const total = (entries) => {
|
|
64
|
+
const totals = { bytes: 2 + Math.max(0, entries.size - 1), members: entries.size, nodes: 1, depth: 1 };
|
|
65
|
+
for (const entry of entries.values()) {
|
|
66
|
+
totals.bytes += entry.keyBytes + entry.totals.bytes;
|
|
67
|
+
totals.members += entry.totals.members;
|
|
68
|
+
totals.nodes += entry.totals.nodes;
|
|
69
|
+
totals.depth = Math.max(totals.depth, 1 + entry.totals.depth);
|
|
70
|
+
}
|
|
71
|
+
return totals;
|
|
72
|
+
};
|
|
73
|
+
const remember = (value) => {
|
|
74
|
+
const entries = /* @__PURE__ */ new Map();
|
|
75
|
+
for (const [key, child] of Object.entries(value)) {
|
|
76
|
+
entries.set(key, {
|
|
77
|
+
keyBytes: Array.isArray(value) ? 0 : encodedStringBytes(key) + 1,
|
|
78
|
+
totals: typeof child === "object" && child !== null ? snapshots.get(child).totals : scalarTotals(typeof child === "string" ? encodedStringBytes(child) : String(child).length)
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
snapshots.set(value, { totals: total(entries), entries });
|
|
82
|
+
};
|
|
83
|
+
const admit = (input, limits = defaultLimits) => {
|
|
84
|
+
const result = BoundedJson.admitStrict(input, limits, {
|
|
85
|
+
ordinaryRecords: true,
|
|
86
|
+
boundedText: true,
|
|
87
|
+
onContainer: remember
|
|
88
|
+
});
|
|
89
|
+
return result.ok ? result : {
|
|
90
|
+
...result,
|
|
91
|
+
path: boundedPath(result.path),
|
|
92
|
+
complaint: result.complaint === "must be dense and have no extra properties" ? "must be a dense array with no extra properties" : result.complaint
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const record = (input, limits = defaultLimits) => {
|
|
96
|
+
const admitted = admit(input, limits);
|
|
97
|
+
return admitted.ok && (admitted.value === null || Array.isArray(admitted.value) || typeof admitted.value !== "object") ? { ok: false, path: "$", complaint: "must be a JSON record" } : admitted;
|
|
98
|
+
};
|
|
99
|
+
const mergeRecords = (base, patch, limits = defaultLimits) => {
|
|
100
|
+
const merge = (left, right, path) => {
|
|
101
|
+
const entries = new Map(snapshots.get(left).entries);
|
|
102
|
+
const result = { ...left };
|
|
103
|
+
for (const [key, entry] of snapshots.get(right).entries) {
|
|
104
|
+
const previous = left[key];
|
|
105
|
+
const next = right[key];
|
|
106
|
+
if (typeof previous === "object" && previous !== null && !Array.isArray(previous) && typeof next === "object" && next !== null && !Array.isArray(next)) {
|
|
107
|
+
const merged = merge(
|
|
108
|
+
previous,
|
|
109
|
+
next,
|
|
110
|
+
childPath(path, key)
|
|
111
|
+
);
|
|
112
|
+
if (!merged.ok) return merged;
|
|
113
|
+
result[key] = merged.value;
|
|
114
|
+
entries.set(key, { keyBytes: entry.keyBytes, totals: snapshots.get(merged.value).totals });
|
|
115
|
+
} else {
|
|
116
|
+
result[key] = next;
|
|
117
|
+
entries.set(key, entry);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const totals = total(entries);
|
|
121
|
+
const complaint = totals.members > limits.maxMembers ? `exceeds the ${limits.maxMembers}-member limit` : totals.nodes > limits.maxNodes ? `exceeds the ${limits.maxNodes}-node limit` : totals.bytes > limits.maxBytes ? `exceeds the ${limits.maxBytes}-byte limit` : totals.depth > limits.maxDepth ? `exceeds the depth limit of ${limits.maxDepth}` : void 0;
|
|
122
|
+
if (complaint !== void 0) return { ok: false, path: boundedPath(path), complaint };
|
|
123
|
+
Object.freeze(result);
|
|
124
|
+
snapshots.set(result, { totals, entries });
|
|
125
|
+
return { ok: true, value: result };
|
|
126
|
+
};
|
|
127
|
+
return merge(base, patch, "$");
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=Boundary.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/internal/Boundary.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Inert JSON admission for plugin configuration and cache identity.\n *\n * Reflection is descriptor-only: accessors never execute, hostile proxies are\n * refused, and accepted values are detached before they are frozen.\n *\n * @private\n * @since 1.0.0-rc.0\n */\n\nimport * as BoundedJson from \"@smthrs/canonical/BoundedJson\"\n\n/**\n * Strict JSON value accepted by the boundary.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport type Json = BoundedJson.Json\n\n/**\n * Resource bounds for one admitted tree.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport type Limits = BoundedJson.StrictLimits\n\n/**\n * Successful admission.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport interface AdmissionSuccess {\n readonly ok: true\n readonly value: Json\n}\n\n/**\n * Refusal with a stable value path.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport interface AdmissionFailure {\n readonly ok: false\n readonly path: string\n readonly complaint: string\n}\n\n/**\n * Result of inert JSON admission.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport type Admission = AdmissionSuccess | AdmissionFailure\n\n/**\n * Default configuration bounds.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const defaultLimits: Limits = Object.freeze({\n maxBytes: 1024 * 1024,\n maxDepth: 64,\n maxMembers: 4_096,\n maxNodes: 8_192,\n maxStringBytes: 64 * 1024,\n maxKeyBytes: 1_024\n})\n\n/**\n * Tests whether a string contains paired UTF-16 surrogate units.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const isWellFormedText = (value: string): boolean => value.isWellFormed()\n\nconst childPath = (path: string, key: string): string =>\n /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`\n\nconst encodedStringBytes = (value: string): number => BoundedJson.encodedStringBytes(value)!\n\n// Paths contain only well-formed text and JSON-escaped keys. Count their JSON\n// bytes without encoding the whole path, reserving quotes and a truncation marker.\nconst boundedPath = (path: string): string => {\n let bytes = 2 + 3\n let prefix = \"\"\n for (const character of path) {\n const point = character.codePointAt(0)!\n bytes += character === \"\\\"\" || character === \"\\\\\"\n ? 2\n : point <= 0x7f\n ? 1\n : point <= 0x7ff\n ? 2\n : point <= 0xffff\n ? 3\n : 4\n if (bytes > 192) return `${prefix}...`\n prefix += character\n }\n return path\n}\n\ninterface Totals {\n bytes: number\n members: number\n nodes: number\n depth: number\n}\n\ninterface Entry {\n readonly keyBytes: number\n readonly totals: Totals\n}\n\ninterface Snapshot {\n readonly totals: Totals\n readonly entries: Map<string, Entry>\n}\n\n// Only detached containers constructed here enter this map. Mutable caller\n// objects and Object.freeze alone never establish admission.\nconst snapshots = new WeakMap<object, Snapshot>()\n\nconst scalarTotals = (bytes: number): Totals => ({ bytes, members: 0, nodes: 1, depth: 0 })\n\nconst total = (entries: ReadonlyMap<string, Entry>): Totals => {\n const totals: Totals = { bytes: 2 + Math.max(0, entries.size - 1), members: entries.size, nodes: 1, depth: 1 }\n for (const entry of entries.values()) {\n totals.bytes += entry.keyBytes + entry.totals.bytes\n totals.members += entry.totals.members\n totals.nodes += entry.totals.nodes\n totals.depth = Math.max(totals.depth, 1 + entry.totals.depth)\n }\n return totals\n}\n\nconst remember = (value: ReadonlyArray<Json> | { readonly [key: string]: Json }): void => {\n const entries = new Map<string, Entry>()\n for (const [key, child] of Object.entries(value)) {\n entries.set(key, {\n keyBytes: Array.isArray(value) ? 0 : encodedStringBytes(key) + 1,\n totals: typeof child === \"object\" && child !== null ?\n snapshots.get(child)!.totals\n : scalarTotals(typeof child === \"string\" ? encodedStringBytes(child) : String(child).length)\n })\n }\n snapshots.set(value, { totals: total(entries), entries })\n}\n\n/**\n * Copies one strict JSON tree under explicit resource bounds.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const admit = (input: unknown, limits: Limits = defaultLimits): Admission => {\n const result = BoundedJson.admitStrict(input, limits, {\n ordinaryRecords: true,\n boundedText: true,\n onContainer: remember\n })\n return result.ok ? result : {\n ...result,\n path: boundedPath(result.path),\n complaint: result.complaint === \"must be dense and have no extra properties\"\n ? \"must be a dense array with no extra properties\" :\n result.complaint\n }\n}\n\n/**\n * Admits only a JSON record at the root.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const record = (\n input: unknown,\n limits: Limits = defaultLimits\n): AdmissionSuccess | AdmissionFailure => {\n const admitted = admit(input, limits)\n return admitted.ok && (admitted.value === null || Array.isArray(admitted.value) || typeof admitted.value !== \"object\")\n ? { ok: false, path: \"$\", complaint: \"must be a JSON record\" }\n : admitted\n}\n\n/**\n * Merges two independently admitted records, retaining unchanged subtrees.\n * Both operands must come from successful admission, and the patch must be a\n * fresh copy: their trees must be disjoint. Each output branch then comes from\n * at most one location in either tree, preserving the no-repeated-reference\n * invariant without walking retained subtrees. Limits apply to the result.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const mergeRecords = (\n base: { readonly [key: string]: Json },\n patch: { readonly [key: string]: Json },\n limits: Limits = defaultLimits\n): Admission => {\n const merge = (\n left: { readonly [key: string]: Json },\n right: { readonly [key: string]: Json },\n path: string\n ): Admission => {\n const entries = new Map(snapshots.get(left)!.entries)\n const result = { ...left }\n for (const [key, entry] of snapshots.get(right)!.entries) {\n const previous = left[key]\n const next = right[key]!\n if (\n typeof previous === \"object\" && previous !== null && !Array.isArray(previous) &&\n typeof next === \"object\" && next !== null && !Array.isArray(next)\n ) {\n const merged = merge(\n previous as { readonly [key: string]: Json },\n next as { readonly [key: string]: Json },\n childPath(path, key)\n )\n if (!merged.ok) return merged\n result[key] = merged.value\n entries.set(key, { keyBytes: entry.keyBytes, totals: snapshots.get(merged.value as object)!.totals })\n } else {\n result[key] = next\n entries.set(key, entry)\n }\n }\n const totals = total(entries)\n const complaint = totals.members > limits.maxMembers ?\n `exceeds the ${limits.maxMembers}-member limit`\n : totals.nodes > limits.maxNodes ?\n `exceeds the ${limits.maxNodes}-node limit`\n : totals.bytes > limits.maxBytes ?\n `exceeds the ${limits.maxBytes}-byte limit`\n : totals.depth > limits.maxDepth ?\n `exceeds the depth limit of ${limits.maxDepth}`\n : undefined\n if (complaint !== undefined) return { ok: false, path: boundedPath(path), complaint }\n Object.freeze(result)\n snapshots.set(result, { totals, entries })\n return { ok: true, value: result }\n }\n return merge(base, patch, \"$\")\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,kBAA6B;AAuDtB,MAAM,gBAAwB,OAAO,OAAO;AAAA,EACjD,UAAU,OAAO;AAAA,EACjB,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,gBAAgB,KAAK;AAAA,EACrB,aAAa;AACf,CAAC;AAQM,MAAM,mBAAmB,CAAC,UAA2B,MAAM,aAAa;AAE/E,MAAM,YAAY,CAAC,MAAc,QAC/B,6BAA6B,KAAK,GAAG,IAAI,GAAG,IAAI,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI,KAAK,UAAU,GAAG,CAAC;AAE5F,MAAM,qBAAqB,CAAC,UAA0B,YAAY,mBAAmB,KAAK;AAI1F,MAAM,cAAc,CAAC,SAAyB;AAC5C,MAAI,QAAQ,IAAI;AAChB,MAAI,SAAS;AACb,aAAW,aAAa,MAAM;AAC5B,UAAM,QAAQ,UAAU,YAAY,CAAC;AACrC,aAAS,cAAc,OAAQ,cAAc,OACzC,IACA,SAAS,MACT,IACA,SAAS,OACT,IACA,SAAS,QACT,IACA;AACJ,QAAI,QAAQ,IAAK,QAAO,GAAG,MAAM;AACjC,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAqBA,MAAM,YAAY,oBAAI,QAA0B;AAEhD,MAAM,eAAe,CAAC,WAA2B,EAAE,OAAO,SAAS,GAAG,OAAO,GAAG,OAAO,EAAE;AAEzF,MAAM,QAAQ,CAAC,YAAgD;AAC7D,QAAM,SAAiB,EAAE,OAAO,IAAI,KAAK,IAAI,GAAG,QAAQ,OAAO,CAAC,GAAG,SAAS,QAAQ,MAAM,OAAO,GAAG,OAAO,EAAE;AAC7G,aAAW,SAAS,QAAQ,OAAO,GAAG;AACpC,WAAO,SAAS,MAAM,WAAW,MAAM,OAAO;AAC9C,WAAO,WAAW,MAAM,OAAO;AAC/B,WAAO,SAAS,MAAM,OAAO;AAC7B,WAAO,QAAQ,KAAK,IAAI,OAAO,OAAO,IAAI,MAAM,OAAO,KAAK;AAAA,EAC9D;AACA,SAAO;AACT;AAEA,MAAM,WAAW,CAAC,UAAwE;AACxF,QAAM,UAAU,oBAAI,IAAmB;AACvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAQ,IAAI,KAAK;AAAA,MACf,UAAU,MAAM,QAAQ,KAAK,IAAI,IAAI,mBAAmB,GAAG,IAAI;AAAA,MAC/D,QAAQ,OAAO,UAAU,YAAY,UAAU,OAC7C,UAAU,IAAI,KAAK,EAAG,SACpB,aAAa,OAAO,UAAU,WAAW,mBAAmB,KAAK,IAAI,OAAO,KAAK,EAAE,MAAM;AAAA,IAC/F,CAAC;AAAA,EACH;AACA,YAAU,IAAI,OAAO,EAAE,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC;AAC1D;AAQO,MAAM,QAAQ,CAAC,OAAgB,SAAiB,kBAA6B;AAClF,QAAM,SAAS,YAAY,YAAY,OAAO,QAAQ;AAAA,IACpD,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,aAAa;AAAA,EACf,CAAC;AACD,SAAO,OAAO,KAAK,SAAS;AAAA,IAC1B,GAAG;AAAA,IACH,MAAM,YAAY,OAAO,IAAI;AAAA,IAC7B,WAAW,OAAO,cAAc,+CAC5B,mDACF,OAAO;AAAA,EACX;AACF;AAQO,MAAM,SAAS,CACpB,OACA,SAAiB,kBACuB;AACxC,QAAM,WAAW,MAAM,OAAO,MAAM;AACpC,SAAO,SAAS,OAAO,SAAS,UAAU,QAAQ,MAAM,QAAQ,SAAS,KAAK,KAAK,OAAO,SAAS,UAAU,YACzG,EAAE,IAAI,OAAO,MAAM,KAAK,WAAW,wBAAwB,IAC3D;AACN;AAYO,MAAM,eAAe,CAC1B,MACA,OACA,SAAiB,kBACH;AACd,QAAM,QAAQ,CACZ,MACA,OACA,SACc;AACd,UAAM,UAAU,IAAI,IAAI,UAAU,IAAI,IAAI,EAAG,OAAO;AACpD,UAAM,SAAS,EAAE,GAAG,KAAK;AACzB,eAAW,CAAC,KAAK,KAAK,KAAK,UAAU,IAAI,KAAK,EAAG,SAAS;AACxD,YAAM,WAAW,KAAK,GAAG;AACzB,YAAM,OAAO,MAAM,GAAG;AACtB,UACE,OAAO,aAAa,YAAY,aAAa,QAAQ,CAAC,MAAM,QAAQ,QAAQ,KAC5E,OAAO,SAAS,YAAY,SAAS,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAChE;AACA,cAAM,SAAS;AAAA,UACb;AAAA,UACA;AAAA,UACA,UAAU,MAAM,GAAG;AAAA,QACrB;AACA,YAAI,CAAC,OAAO,GAAI,QAAO;AACvB,eAAO,GAAG,IAAI,OAAO;AACrB,gBAAQ,IAAI,KAAK,EAAE,UAAU,MAAM,UAAU,QAAQ,UAAU,IAAI,OAAO,KAAe,EAAG,OAAO,CAAC;AAAA,MACtG,OAAO;AACL,eAAO,GAAG,IAAI;AACd,gBAAQ,IAAI,KAAK,KAAK;AAAA,MACxB;AAAA,IACF;AACA,UAAM,SAAS,MAAM,OAAO;AAC5B,UAAM,YAAY,OAAO,UAAU,OAAO,aACxC,eAAe,OAAO,UAAU,kBAC9B,OAAO,QAAQ,OAAO,WACxB,eAAe,OAAO,QAAQ,gBAC5B,OAAO,QAAQ,OAAO,WACxB,eAAe,OAAO,QAAQ,gBAC5B,OAAO,QAAQ,OAAO,WACxB,8BAA8B,OAAO,QAAQ,KAC3C;AACJ,QAAI,cAAc,OAAW,QAAO,EAAE,IAAI,OAAO,MAAM,YAAY,IAAI,GAAG,UAAU;AACpF,WAAO,OAAO,MAAM;AACpB,cAAU,IAAI,QAAQ,EAAE,QAAQ,QAAQ,CAAC;AACzC,WAAO,EAAE,IAAI,MAAM,OAAO,OAAO;AAAA,EACnC;AACA,SAAO,MAAM,MAAM,OAAO,GAAG;AAC/B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect layer composition for a resolved plugin list.
|
|
3
|
+
*
|
|
4
|
+
* @private
|
|
5
|
+
* @since 1.0.0-rc.0
|
|
6
|
+
*/
|
|
7
|
+
import { Action } from "@smthrs/flow";
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import type { FlowsPlugin } from "../Plugin.ts";
|
|
10
|
+
import { PluginError } from "../PluginError.ts";
|
|
11
|
+
/**
|
|
12
|
+
* Merges plugin layers left-to-right, wrapping each build failure as
|
|
13
|
+
* `layer_failed`, then seals the cache environment: it is supplied beneath
|
|
14
|
+
* the plugin layers and overrides anything they output, and an absent
|
|
15
|
+
* declaration stays absent.
|
|
16
|
+
*
|
|
17
|
+
* @private
|
|
18
|
+
* @since 1.0.0-rc.0
|
|
19
|
+
*/
|
|
20
|
+
export declare const mergePluginLayers: <H>(plugins: ReadonlyArray<FlowsPlugin<H>>, cacheEnvironment: Action.CacheEnvironment | undefined) => Layer.Layer<any, PluginError, any>;
|
|
21
|
+
//# sourceMappingURL=mergePluginLayers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergePluginLayers.d.ts","sourceRoot":"","sources":["../../../src/internal/mergePluginLayers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EACjC,SAAS,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EACtC,kBAAkB,MAAM,CAAC,gBAAgB,GAAG,SAAS,KACpD,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,CA+BnC,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var mergePluginLayers_exports = {};
|
|
30
|
+
__export(mergePluginLayers_exports, {
|
|
31
|
+
mergePluginLayers: () => mergePluginLayers
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(mergePluginLayers_exports);
|
|
34
|
+
var import_flow = require("@smthrs/flow");
|
|
35
|
+
var Effect = __toESM(require("effect/Effect"), 1);
|
|
36
|
+
var Layer = __toESM(require("effect/Layer"), 1);
|
|
37
|
+
var import_PluginError = require("../PluginError.js");
|
|
38
|
+
const mergePluginLayers = (plugins, cacheEnvironment) => {
|
|
39
|
+
const layers = plugins.flatMap(
|
|
40
|
+
(plugin) => plugin.layer ? [
|
|
41
|
+
Layer.catchCause(plugin.layer, (cause) => Layer.effectDiscard(
|
|
42
|
+
Effect.fail(
|
|
43
|
+
new import_PluginError.PluginError({
|
|
44
|
+
code: "layer_failed",
|
|
45
|
+
message: `plugin "${plugin.name}" failed to build its layer`,
|
|
46
|
+
plugin: plugin.name,
|
|
47
|
+
cause
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
))
|
|
51
|
+
] : []
|
|
52
|
+
);
|
|
53
|
+
const merged = layers.length === 0 ? Layer.empty : layers.reduce((accumulated, next) => Layer.provideMerge(next, accumulated));
|
|
54
|
+
const environment = Layer.succeed(import_flow.Action.CurrentCacheEnvironment)(cacheEnvironment);
|
|
55
|
+
return Layer.merge(Layer.provideMerge(merged, environment), environment);
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=mergePluginLayers.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/internal/mergePluginLayers.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Effect layer composition for a resolved plugin list.\n *\n * @private\n * @since 1.0.0-rc.0\n */\n\nimport { Action } from \"@smthrs/flow\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport type { FlowsPlugin } from \"../Plugin.ts\"\nimport { PluginError } from \"../PluginError.ts\"\n\n/**\n * Merges plugin layers left-to-right, wrapping each build failure as\n * `layer_failed`, then seals the cache environment: it is supplied beneath\n * the plugin layers and overrides anything they output, and an absent\n * declaration stays absent.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const mergePluginLayers = <H>(\n plugins: ReadonlyArray<FlowsPlugin<H>>,\n cacheEnvironment: Action.CacheEnvironment | undefined\n): Layer.Layer<any, PluginError, any> => {\n const layers = plugins.flatMap((plugin) =>\n plugin.layer\n ? [\n Layer.catchCause(plugin.layer, (cause) =>\n Layer.effectDiscard(\n Effect.fail(\n new PluginError({\n code: \"layer_failed\",\n message: `plugin \"${plugin.name}\" failed to build its layer`,\n plugin: plugin.name,\n cause\n })\n )\n )) as Layer.Layer<any, PluginError, any>\n ]\n : []\n )\n const merged = (layers.length === 0\n ? Layer.empty\n : layers.reduce((accumulated, next) => Layer.provideMerge(next, accumulated))) as Layer.Layer<any, PluginError, any>\n // The sealed environment is provided beneath the plugin layers so they can\n // read it, then merged last so it overrides any plugin output. An absent\n // declaration is sealed as `undefined`, so no plugin layer can declare or\n // replace the composition's cache identity.\n const environment = Layer.succeed(Action.CurrentCacheEnvironment)(cacheEnvironment) as unknown as Layer.Layer<\n any,\n PluginError,\n any\n >\n return Layer.merge(Layer.provideMerge(merged, environment), environment)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,kBAAuB;AACvB,aAAwB;AACxB,YAAuB;AAEvB,yBAA4B;AAWrB,MAAM,oBAAoB,CAC/B,SACA,qBACuC;AACvC,QAAM,SAAS,QAAQ;AAAA,IAAQ,CAAC,WAC9B,OAAO,QACH;AAAA,MACA,MAAM,WAAW,OAAO,OAAO,CAAC,UAC9B,MAAM;AAAA,QACJ,OAAO;AAAA,UACL,IAAI,+BAAY;AAAA,YACd,MAAM;AAAA,YACN,SAAS,WAAW,OAAO,IAAI;AAAA,YAC/B,QAAQ,OAAO;AAAA,YACf;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACL,IACE,CAAC;AAAA,EACP;AACA,QAAM,SAAU,OAAO,WAAW,IAC9B,MAAM,QACN,OAAO,OAAO,CAAC,aAAa,SAAS,MAAM,aAAa,MAAM,WAAW,CAAC;AAK9E,QAAM,cAAc,MAAM,QAAQ,mBAAO,uBAAuB,EAAE,gBAAgB;AAKlF,SAAO,MAAM,MAAM,MAAM,aAAa,QAAQ,WAAW,GAAG,WAAW;AACzE;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache identity admission for a resolved plugin list.
|
|
3
|
+
*
|
|
4
|
+
* @private
|
|
5
|
+
* @since 1.0.0-rc.0
|
|
6
|
+
*/
|
|
7
|
+
import { Action } from "@smthrs/flow";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import type { FlowsPlugin } from "../Plugin.ts";
|
|
10
|
+
import { PluginError } from "../PluginError.ts";
|
|
11
|
+
/**
|
|
12
|
+
* Admits a caller cache environment and prepends one escaped `name@version`
|
|
13
|
+
* identity per plugin, in resolved order. An absent input stays absent. A
|
|
14
|
+
* versionless plugin is refused at the dollar-path it was admitted from.
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
* @since 1.0.0-rc.0
|
|
18
|
+
*/
|
|
19
|
+
export declare const snapshotCacheEnvironment: <H>(input: unknown, plugins: ReadonlyArray<{
|
|
20
|
+
readonly plugin: FlowsPlugin<H>;
|
|
21
|
+
readonly path: string;
|
|
22
|
+
}>) => Effect.Effect<Action.CacheEnvironment | undefined, PluginError>;
|
|
23
|
+
//# sourceMappingURL=snapshotCacheEnvironment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshotCacheEnvironment.d.ts","sourceRoot":"","sources":["../../../src/internal/snapshotCacheEnvironment.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAO/C;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,GAAI,CAAC,EACxC,OAAO,OAAO,EACd,SAAS,aAAa,CAAC;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,KACjF,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,GAAG,SAAS,EAAE,WAAW,CAgDhE,CAAA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var snapshotCacheEnvironment_exports = {};
|
|
30
|
+
__export(snapshotCacheEnvironment_exports, {
|
|
31
|
+
snapshotCacheEnvironment: () => snapshotCacheEnvironment
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(snapshotCacheEnvironment_exports);
|
|
34
|
+
var import_flow = require("@smthrs/flow");
|
|
35
|
+
var Effect = __toESM(require("effect/Effect"), 1);
|
|
36
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
37
|
+
var import_PluginError = require("../PluginError.js");
|
|
38
|
+
var Boundary = __toESM(require("./Boundary.js"), 1);
|
|
39
|
+
const escapePluginIdentityPart = (value) => (
|
|
40
|
+
// Percent must be escaped first so literal escape-looking text remains distinct from the `@` escape added next.
|
|
41
|
+
value.replaceAll("%", "%25").replaceAll("@", "%40")
|
|
42
|
+
);
|
|
43
|
+
const snapshotCacheEnvironment = (input, plugins) => {
|
|
44
|
+
if (input === void 0) return Effect.succeed(void 0);
|
|
45
|
+
const pluginIdentities = [];
|
|
46
|
+
for (const { path, plugin } of plugins) {
|
|
47
|
+
if (plugin.version === void 0) {
|
|
48
|
+
return Effect.fail(
|
|
49
|
+
new import_PluginError.PluginError({
|
|
50
|
+
code: "cache_environment_invalid",
|
|
51
|
+
message: `cache environment requires a version for plugin "${plugin.name}"`,
|
|
52
|
+
path: `${path}.version`,
|
|
53
|
+
plugin: plugin.name
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
pluginIdentities.push(`${escapePluginIdentityPart(plugin.name)}@${escapePluginIdentityPart(plugin.version)}`);
|
|
58
|
+
}
|
|
59
|
+
const admitted = Boundary.record(input);
|
|
60
|
+
if (!admitted.ok) {
|
|
61
|
+
return Effect.fail(
|
|
62
|
+
new import_PluginError.PluginError({
|
|
63
|
+
code: "cache_environment_invalid",
|
|
64
|
+
message: `cache environment ${admitted.complaint}`,
|
|
65
|
+
path: `$options.cacheEnvironment${admitted.path.slice(1)}`
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return Schema.decodeUnknownEffect(import_flow.Action.CacheEnvironment)(admitted.value).pipe(
|
|
70
|
+
Effect.mapError(
|
|
71
|
+
() => new import_PluginError.PluginError({
|
|
72
|
+
code: "cache_environment_invalid",
|
|
73
|
+
message: "cache environment does not match the complete cache identity schema",
|
|
74
|
+
path: "$options.cacheEnvironment"
|
|
75
|
+
})
|
|
76
|
+
),
|
|
77
|
+
Effect.map((environment) => {
|
|
78
|
+
const capabilities = {};
|
|
79
|
+
for (const name of Object.keys(environment.capabilities)) {
|
|
80
|
+
Object.defineProperty(capabilities, name, {
|
|
81
|
+
value: Object.freeze([...environment.capabilities[name]]),
|
|
82
|
+
enumerable: true
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze({
|
|
86
|
+
layers: Object.freeze([...pluginIdentities, ...environment.layers]),
|
|
87
|
+
capabilities: Object.freeze(capabilities)
|
|
88
|
+
});
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=snapshotCacheEnvironment.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/internal/snapshotCacheEnvironment.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Cache identity admission for a resolved plugin list.\n *\n * @private\n * @since 1.0.0-rc.0\n */\n\nimport { Action } from \"@smthrs/flow\"\nimport * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\nimport type { FlowsPlugin } from \"../Plugin.ts\"\nimport { PluginError } from \"../PluginError.ts\"\nimport * as Boundary from \"./Boundary.ts\"\n\nconst escapePluginIdentityPart = (value: string): string =>\n // Percent must be escaped first so literal escape-looking text remains distinct from the `@` escape added next.\n value.replaceAll(\"%\", \"%25\").replaceAll(\"@\", \"%40\")\n\n/**\n * Admits a caller cache environment and prepends one escaped `name@version`\n * identity per plugin, in resolved order. An absent input stays absent. A\n * versionless plugin is refused at the dollar-path it was admitted from.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const snapshotCacheEnvironment = <H>(\n input: unknown,\n plugins: ReadonlyArray<{ readonly plugin: FlowsPlugin<H>; readonly path: string }>\n): Effect.Effect<Action.CacheEnvironment | undefined, PluginError> => {\n if (input === undefined) return Effect.succeed(undefined)\n const pluginIdentities: Array<string> = []\n for (const { path, plugin } of plugins) {\n if (plugin.version === undefined) {\n return Effect.fail(\n new PluginError({\n code: \"cache_environment_invalid\",\n message: `cache environment requires a version for plugin \"${plugin.name}\"`,\n path: `${path}.version`,\n plugin: plugin.name\n })\n )\n }\n pluginIdentities.push(`${escapePluginIdentityPart(plugin.name)}@${escapePluginIdentityPart(plugin.version)}`)\n }\n const admitted = Boundary.record(input)\n if (!admitted.ok) {\n return Effect.fail(\n new PluginError({\n code: \"cache_environment_invalid\",\n message: `cache environment ${admitted.complaint}`,\n path: `$options.cacheEnvironment${admitted.path.slice(1)}`\n })\n )\n }\n return Schema.decodeUnknownEffect(Action.CacheEnvironment)(admitted.value).pipe(\n Effect.mapError(() =>\n new PluginError({\n code: \"cache_environment_invalid\",\n message: \"cache environment does not match the complete cache identity schema\",\n path: \"$options.cacheEnvironment\"\n })\n ),\n Effect.map((environment) => {\n const capabilities: Record<string, ReadonlyArray<string>> = {}\n for (const name of Object.keys(environment.capabilities)) {\n Object.defineProperty(capabilities, name, {\n value: Object.freeze([...environment.capabilities[name]!]),\n enumerable: true\n })\n }\n return Object.freeze({\n layers: Object.freeze([...pluginIdentities, ...environment.layers]),\n capabilities: Object.freeze(capabilities)\n })\n })\n )\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,kBAAuB;AACvB,aAAwB;AACxB,aAAwB;AAExB,yBAA4B;AAC5B,eAA0B;AAE1B,MAAM,2BAA2B,CAAC;AAAA;AAAA,EAEhC,MAAM,WAAW,KAAK,KAAK,EAAE,WAAW,KAAK,KAAK;AAAA;AAU7C,MAAM,2BAA2B,CACtC,OACA,YACoE;AACpE,MAAI,UAAU,OAAW,QAAO,OAAO,QAAQ,MAAS;AACxD,QAAM,mBAAkC,CAAC;AACzC,aAAW,EAAE,MAAM,OAAO,KAAK,SAAS;AACtC,QAAI,OAAO,YAAY,QAAW;AAChC,aAAO,OAAO;AAAA,QACZ,IAAI,+BAAY;AAAA,UACd,MAAM;AAAA,UACN,SAAS,oDAAoD,OAAO,IAAI;AAAA,UACxE,MAAM,GAAG,IAAI;AAAA,UACb,QAAQ,OAAO;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF;AACA,qBAAiB,KAAK,GAAG,yBAAyB,OAAO,IAAI,CAAC,IAAI,yBAAyB,OAAO,OAAO,CAAC,EAAE;AAAA,EAC9G;AACA,QAAM,WAAW,SAAS,OAAO,KAAK;AACtC,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,OAAO;AAAA,MACZ,IAAI,+BAAY;AAAA,QACd,MAAM;AAAA,QACN,SAAS,qBAAqB,SAAS,SAAS;AAAA,QAChD,MAAM,4BAA4B,SAAS,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,OAAO,oBAAoB,mBAAO,gBAAgB,EAAE,SAAS,KAAK,EAAE;AAAA,IACzE,OAAO;AAAA,MAAS,MACd,IAAI,+BAAY;AAAA,QACd,MAAM;AAAA,QACN,SAAS;AAAA,QACT,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,IACA,OAAO,IAAI,CAAC,gBAAgB;AAC1B,YAAM,eAAsD,CAAC;AAC7D,iBAAW,QAAQ,OAAO,KAAK,YAAY,YAAY,GAAG;AACxD,eAAO,eAAe,cAAc,MAAM;AAAA,UACxC,OAAO,OAAO,OAAO,CAAC,GAAG,YAAY,aAAa,IAAI,CAAE,CAAC;AAAA,UACzD,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AACA,aAAO,OAAO,OAAO;AAAA,QACnB,QAAQ,OAAO,OAAO,CAAC,GAAG,kBAAkB,GAAG,YAAY,MAAM,CAAC;AAAA,QAClE,cAAc,OAAO,OAAO,YAAY;AAAA,MAC1C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded JSON configuration consumed and produced by the plugin kernel.
|
|
3
|
+
*
|
|
4
|
+
* Configuration is an extension namespace, not an engine-policy surface.
|
|
5
|
+
* Durable retry, concurrency, and storage policy stay on their owning Effect
|
|
6
|
+
* services and constructor options. Every accepted value is copied before any
|
|
7
|
+
* plugin observes it, then frozen recursively.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.0.0-rc.0
|
|
10
|
+
*/
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Schema from "effect/Schema";
|
|
13
|
+
import { PluginError } from "./PluginError.ts";
|
|
14
|
+
/**
|
|
15
|
+
* Maximum encoded bytes accepted for one plugin configuration.
|
|
16
|
+
*
|
|
17
|
+
* @category limits
|
|
18
|
+
* @since 1.0.0-rc.0
|
|
19
|
+
*/
|
|
20
|
+
export declare const maximumConfigBytes: number;
|
|
21
|
+
/**
|
|
22
|
+
* Maximum nesting accepted for one plugin configuration.
|
|
23
|
+
*
|
|
24
|
+
* @category limits
|
|
25
|
+
* @since 1.0.0-rc.0
|
|
26
|
+
*/
|
|
27
|
+
export declare const maximumConfigDepth: number;
|
|
28
|
+
/**
|
|
29
|
+
* Maximum aggregate members accepted for one plugin configuration.
|
|
30
|
+
*
|
|
31
|
+
* @category limits
|
|
32
|
+
* @since 1.0.0-rc.0
|
|
33
|
+
*/
|
|
34
|
+
export declare const maximumConfigMembers: number;
|
|
35
|
+
/**
|
|
36
|
+
* Maximum aggregate values accepted for one plugin configuration.
|
|
37
|
+
*
|
|
38
|
+
* @category limits
|
|
39
|
+
* @since 1.0.0-rc.0
|
|
40
|
+
*/
|
|
41
|
+
export declare const maximumConfigNodes: number;
|
|
42
|
+
/**
|
|
43
|
+
* One value accepted in a plugin-owned configuration namespace.
|
|
44
|
+
*
|
|
45
|
+
* @category models
|
|
46
|
+
* @since 1.0.0-rc.0
|
|
47
|
+
*/
|
|
48
|
+
export declare const ConfigValue: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
49
|
+
/**
|
|
50
|
+
* One value accepted in a plugin-owned configuration namespace.
|
|
51
|
+
*
|
|
52
|
+
* @category models
|
|
53
|
+
* @since 1.0.0-rc.0
|
|
54
|
+
*/
|
|
55
|
+
export type ConfigValue = typeof ConfigValue.Type;
|
|
56
|
+
/**
|
|
57
|
+
* Admits pre-resolution configuration as a detached, recursively frozen snapshot.
|
|
58
|
+
*
|
|
59
|
+
* Keys name plugin-owned namespaces. `engine`, `retry`, `store`, and
|
|
60
|
+
* `plugins` are refused because accepting those names would imply policy the
|
|
61
|
+
* plugin kernel does not own or apply.
|
|
62
|
+
*
|
|
63
|
+
* @category models
|
|
64
|
+
* @since 1.0.0-rc.0
|
|
65
|
+
*/
|
|
66
|
+
export declare const FlowsConfig: Schema.decodeTo<Schema.declare<Readonly<Record<string, Schema.Json>>, Readonly<Record<string, Schema.Json>>>, Schema.Unknown, never, never>;
|
|
67
|
+
/**
|
|
68
|
+
* The decoded form of {@link FlowsConfig}.
|
|
69
|
+
*
|
|
70
|
+
* @category models
|
|
71
|
+
* @since 1.0.0-rc.0
|
|
72
|
+
*/
|
|
73
|
+
export type FlowsConfig = typeof FlowsConfig.Type;
|
|
74
|
+
/**
|
|
75
|
+
* Admits the detached, recursively frozen configuration handed to plugins.
|
|
76
|
+
*
|
|
77
|
+
* @category models
|
|
78
|
+
* @since 1.0.0-rc.0
|
|
79
|
+
*/
|
|
80
|
+
export declare const ResolvedConfig: Schema.decodeTo<Schema.declare<Readonly<Record<string, Schema.Json>>, Readonly<Record<string, Schema.Json>>>, Schema.Unknown, never, never>;
|
|
81
|
+
/**
|
|
82
|
+
* The decoded form of {@link ResolvedConfig}.
|
|
83
|
+
*
|
|
84
|
+
* @category models
|
|
85
|
+
* @since 1.0.0-rc.0
|
|
86
|
+
*/
|
|
87
|
+
export type ResolvedConfig = typeof ResolvedConfig.Type;
|
|
88
|
+
/**
|
|
89
|
+
* Empty defaults. Engine policy is deliberately not defaulted here.
|
|
90
|
+
*
|
|
91
|
+
* @category constructors
|
|
92
|
+
* @since 1.0.0-rc.0
|
|
93
|
+
*/
|
|
94
|
+
export declare const defaults: ResolvedConfig;
|
|
95
|
+
/**
|
|
96
|
+
* Copies and deep-merges a configuration patch over a base configuration.
|
|
97
|
+
*
|
|
98
|
+
* Records merge key-by-key and every other JSON value replaces wholesale.
|
|
99
|
+
* Raw operands are admitted; known snapshots retain unchanged subtrees.
|
|
100
|
+
* Cached subtree totals enforce merged output bounds. Unsafe property names,
|
|
101
|
+
* accessors, cycles, exotic prototypes, and aggregate values outside the
|
|
102
|
+
* resource limits fail with `config_invalid`.
|
|
103
|
+
*
|
|
104
|
+
* @category combinators
|
|
105
|
+
* @since 1.0.0-rc.0
|
|
106
|
+
*/
|
|
107
|
+
export declare const merge: (base: FlowsConfig, patch: unknown) => FlowsConfig;
|
|
108
|
+
/**
|
|
109
|
+
* Copies and freezes one JSON value without retaining caller-owned objects.
|
|
110
|
+
*
|
|
111
|
+
* @category utils
|
|
112
|
+
* @since 1.0.0-rc.0
|
|
113
|
+
*/
|
|
114
|
+
export declare const deepFreeze: <A extends ConfigValue>(value: A) => A;
|
|
115
|
+
/**
|
|
116
|
+
* Admits a raw pre-resolution configuration as an immutable snapshot.
|
|
117
|
+
*
|
|
118
|
+
* @category constructors
|
|
119
|
+
* @since 1.0.0-rc.0
|
|
120
|
+
*/
|
|
121
|
+
export declare const snapshot: (config: unknown) => Effect.Effect<FlowsConfig, PluginError>;
|
|
122
|
+
/**
|
|
123
|
+
* Decodes the post-waterfall configuration into its final immutable form.
|
|
124
|
+
*
|
|
125
|
+
* @category constructors
|
|
126
|
+
* @since 1.0.0-rc.0
|
|
127
|
+
*/
|
|
128
|
+
export declare const resolve: (config: unknown) => Effect.Effect<ResolvedConfig, PluginError>;
|
|
129
|
+
//# sourceMappingURL=Config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../src/Config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAoC,CAAA;AAErE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,WAAW,sDAAc,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAwBjD;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,6IAAsB,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,6IAAsB,CAAA;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAyBvD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,cAAmC,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,GAAI,MAAM,WAAW,EAAE,OAAO,OAAO,KAAG,WAUzD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,KAAG,CAI5D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CACU,CAAA;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAqB,CAAA"}
|