@coderifts/agent-guard 6.1.0 → 6.3.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 (66) hide show
  1. package/README.md +68 -2
  2. package/dist/cjs/cas-adapters/api.d.ts +94 -0
  3. package/dist/cjs/cas-adapters/api.d.ts.map +1 -0
  4. package/dist/cjs/cas-adapters/api.js +120 -0
  5. package/dist/cjs/cas-adapters/api.js.map +1 -0
  6. package/dist/cjs/cas-adapters/db.d.ts +93 -0
  7. package/dist/cjs/cas-adapters/db.d.ts.map +1 -0
  8. package/dist/cjs/cas-adapters/db.js +139 -0
  9. package/dist/cjs/cas-adapters/db.js.map +1 -0
  10. package/dist/cjs/cas-adapters/fs.d.ts +79 -0
  11. package/dist/cjs/cas-adapters/fs.d.ts.map +1 -0
  12. package/dist/cjs/cas-adapters/fs.js +224 -0
  13. package/dist/cjs/cas-adapters/fs.js.map +1 -0
  14. package/dist/cjs/cas-adapters/registry.d.ts +88 -0
  15. package/dist/cjs/cas-adapters/registry.d.ts.map +1 -0
  16. package/dist/cjs/cas-adapters/registry.js +120 -0
  17. package/dist/cjs/cas-adapters/registry.js.map +1 -0
  18. package/dist/cjs/cas-attestation.d.ts +94 -0
  19. package/dist/cjs/cas-attestation.d.ts.map +1 -0
  20. package/dist/cjs/cas-attestation.js +133 -0
  21. package/dist/cjs/cas-attestation.js.map +1 -0
  22. package/dist/cjs/conditional-write.d.ts +66 -0
  23. package/dist/cjs/conditional-write.d.ts.map +1 -1
  24. package/dist/cjs/conditional-write.js +72 -1
  25. package/dist/cjs/conditional-write.js.map +1 -1
  26. package/dist/cjs/index.d.ts +11 -2
  27. package/dist/cjs/index.d.ts.map +1 -1
  28. package/dist/cjs/index.js +44 -3
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/cjs/with-coderifts.d.ts +8 -0
  31. package/dist/cjs/with-coderifts.d.ts.map +1 -1
  32. package/dist/cjs/with-coderifts.js +3 -0
  33. package/dist/cjs/with-coderifts.js.map +1 -1
  34. package/dist/esm/cas-adapters/api.d.ts +94 -0
  35. package/dist/esm/cas-adapters/api.d.ts.map +1 -0
  36. package/dist/esm/cas-adapters/api.js +116 -0
  37. package/dist/esm/cas-adapters/api.js.map +1 -0
  38. package/dist/esm/cas-adapters/db.d.ts +93 -0
  39. package/dist/esm/cas-adapters/db.d.ts.map +1 -0
  40. package/dist/esm/cas-adapters/db.js +135 -0
  41. package/dist/esm/cas-adapters/db.js.map +1 -0
  42. package/dist/esm/cas-adapters/fs.d.ts +79 -0
  43. package/dist/esm/cas-adapters/fs.d.ts.map +1 -0
  44. package/dist/esm/cas-adapters/fs.js +185 -0
  45. package/dist/esm/cas-adapters/fs.js.map +1 -0
  46. package/dist/esm/cas-adapters/registry.d.ts +88 -0
  47. package/dist/esm/cas-adapters/registry.d.ts.map +1 -0
  48. package/dist/esm/cas-adapters/registry.js +116 -0
  49. package/dist/esm/cas-adapters/registry.js.map +1 -0
  50. package/dist/esm/cas-attestation.d.ts +94 -0
  51. package/dist/esm/cas-attestation.d.ts.map +1 -0
  52. package/dist/esm/cas-attestation.js +127 -0
  53. package/dist/esm/cas-attestation.js.map +1 -0
  54. package/dist/esm/conditional-write.d.ts +66 -0
  55. package/dist/esm/conditional-write.d.ts.map +1 -1
  56. package/dist/esm/conditional-write.js +69 -0
  57. package/dist/esm/conditional-write.js.map +1 -1
  58. package/dist/esm/index.d.ts +11 -2
  59. package/dist/esm/index.d.ts.map +1 -1
  60. package/dist/esm/index.js +14 -2
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/with-coderifts.d.ts +8 -0
  63. package/dist/esm/with-coderifts.d.ts.map +1 -1
  64. package/dist/esm/with-coderifts.js +3 -0
  65. package/dist/esm/with-coderifts.js.map +1 -1
  66. package/package.json +1 -1
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Filesystem CAS adapter — mtime + content-hash VersionToken and atomic-rename write.
3
+ *
4
+ * Uses the host contract helper executeIfUnchanged (conditional-write.ts). Does not invent
5
+ * a parallel outcome shape. Token format is opaque to the guard (string equality only).
6
+ *
7
+ * Token encoding (this adapter only; not interpreted by the core):
8
+ * fs:v1:<mtime_ms>:<sha256_hex_of_file_bytes>
9
+ * Missing file → createFsVersionToken still works for "absent" via a dedicated absent token
10
+ * only if we choose; for create we require the file to exist (ENOENT throws) so hosts
11
+ * measure an existing prior. For write of new files, expected_token may be ABSENT_TOKEN.
12
+ */
13
+ 'use strict';
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.tokensEqual = exports.FS_ABSENT_TOKEN = exports.FS_VERSION_TOKEN_PREFIX = void 0;
49
+ exports.fsTokenContentHash = fsTokenContentHash;
50
+ exports.createFsVersionToken = createFsVersionToken;
51
+ exports.readVersionedFile = readVersionedFile;
52
+ exports.writeFileIfUnchanged = writeFileIfUnchanged;
53
+ exports.createFsPriorContentResolver = createFsPriorContentResolver;
54
+ const node_crypto_1 = require("node:crypto");
55
+ const node_fs_1 = require("node:fs");
56
+ const path = __importStar(require("node:path"));
57
+ const conditional_write_js_1 = require("../conditional-write.js");
58
+ Object.defineProperty(exports, "tokensEqual", { enumerable: true, get: function () { return conditional_write_js_1.tokensEqual; } });
59
+ /** Prefix for this adapter's opaque tokens (equality-only outside this module). */
60
+ exports.FS_VERSION_TOKEN_PREFIX = 'fs:v1:';
61
+ /**
62
+ * Token used when the path does not exist yet (create-if-absent CAS).
63
+ * Hosts that measured absence should pass this as expected_token for first write.
64
+ */
65
+ exports.FS_ABSENT_TOKEN = 'fs:v1:absent';
66
+ function sha256hex(buf) {
67
+ return (0, node_crypto_1.createHash)('sha256').update(buf).digest('hex');
68
+ }
69
+ /** Extract content-hash segment from an fs:v1 token (null if absent/malformed). */
70
+ function fsTokenContentHash(token) {
71
+ if (typeof token !== 'string' || !token.startsWith(exports.FS_VERSION_TOKEN_PREFIX))
72
+ return null;
73
+ if (token === exports.FS_ABSENT_TOKEN)
74
+ return null;
75
+ const rest = token.slice(exports.FS_VERSION_TOKEN_PREFIX.length);
76
+ const colon = rest.indexOf(':');
77
+ if (colon < 0)
78
+ return null;
79
+ const hash = rest.slice(colon + 1);
80
+ return /^[a-f0-9]{64}$/.test(hash) ? hash : null;
81
+ }
82
+ /**
83
+ * Build a VersionToken from path: mtime (ms) + sha256 of file bytes.
84
+ * Throws on I/O errors other than callers may catch. ENOENT → returns FS_ABSENT_TOKEN
85
+ * so hosts can CAS create vs create-raced.
86
+ */
87
+ async function createFsVersionToken(filePath) {
88
+ let st;
89
+ try {
90
+ st = await node_fs_1.promises.stat(filePath);
91
+ }
92
+ catch (err) {
93
+ const code = err && typeof err === 'object' && 'code' in err
94
+ ? String(err.code)
95
+ : '';
96
+ if (code === 'ENOENT')
97
+ return exports.FS_ABSENT_TOKEN;
98
+ throw err;
99
+ }
100
+ if (!st.isFile()) {
101
+ // Directories / specials are not content CAS targets for this adapter.
102
+ throw new Error(`createFsVersionToken: not a regular file: ${filePath}`);
103
+ }
104
+ const buf = await node_fs_1.promises.readFile(filePath);
105
+ const hash = sha256hex(buf);
106
+ const mtimeMs = Math.trunc(st.mtimeMs);
107
+ return `${exports.FS_VERSION_TOKEN_PREFIX}${mtimeMs}:${hash}`;
108
+ }
109
+ /**
110
+ * Read file content + version token for VersionedContent (host reporting / preflight prior).
111
+ * ENOENT → content '' and FS_ABSENT_TOKEN.
112
+ */
113
+ async function readVersionedFile(filePath) {
114
+ const version_token = await createFsVersionToken(filePath);
115
+ if (version_token === exports.FS_ABSENT_TOKEN) {
116
+ return { content: '', version_token };
117
+ }
118
+ const content = await node_fs_1.promises.readFile(filePath, 'utf8');
119
+ return { content, version_token };
120
+ }
121
+ /**
122
+ * Conditional write: re-stat+re-hash; if token matches expected → temp file + atomic rename.
123
+ *
124
+ * MEASURED windows (pre-fix, 2fcd74e-era):
125
+ * 1. executeIfUnchanged: current_token() then await write() — no re-check in between.
126
+ * 2. write(): writeFile(tmp) then rename(tmp,target) with NO re-stat of target before rename
127
+ * (fs.ts former lines 106–108) — concurrent mutation of target is clobbered by rename.
128
+ *
129
+ * Closures:
130
+ * - Pre-rename: re-createFsVersionToken(target); on mismatch abort rename, unlink tmp,
131
+ * throw StaleVersionTokenAbort → refused/stale_version_token (write did not land).
132
+ * - Post-rename: detect_stale_during_commit — content-hash of path must match sha256(body);
133
+ * mismatch → committed_stale_detected (write landed; someone overwrote after rename).
134
+ *
135
+ * Wired through executeIfUnchanged — not a parallel path.
136
+ */
137
+ async function writeFileIfUnchanged(args) {
138
+ const target = path.resolve(args.path);
139
+ const body = typeof args.content === 'string' ? Buffer.from(args.content, 'utf8') : args.content;
140
+ const writtenHash = sha256hex(body);
141
+ return (0, conditional_write_js_1.executeIfUnchanged)({
142
+ expected_token: args.expected_token,
143
+ current_token: () => createFsVersionToken(target),
144
+ detect_stale_during_commit: true,
145
+ // Post-commit: token content-hash must equal sha256 of what we wrote (mtime may vary).
146
+ expected_after_commit: async (result) => {
147
+ // Synthesize a comparable token: re-read path; equality is content-hash based via tokensEqual
148
+ // only if full token matches — mtime always changes on write, so we return the LIVE post
149
+ // token only when its hash matches writtenHash; else return a sentinel that cannot match.
150
+ const post = await createFsVersionToken(target);
151
+ const postHash = fsTokenContentHash(post);
152
+ if (postHash === result.written_content_hash)
153
+ return post;
154
+ // Force mismatch → committed_stale_detected (detection, not rollback).
155
+ return `${exports.FS_VERSION_TOKEN_PREFIX}0:stale_during_commit_mismatch`;
156
+ },
157
+ write: async () => {
158
+ const dir = path.dirname(target);
159
+ await node_fs_1.promises.mkdir(dir, { recursive: true });
160
+ const tmp = path.join(dir, `.coderifts-cas-${path.basename(target)}-${process.pid}-${(0, node_crypto_1.randomBytes)(6).toString('hex')}.tmp`);
161
+ try {
162
+ await node_fs_1.promises.writeFile(tmp, body);
163
+ // Close pre-rename window: if target moved since the executeIfUnchanged check, do not clobber.
164
+ const still = await createFsVersionToken(target);
165
+ if (!(0, conditional_write_js_1.tokensEqual)(args.expected_token, still)) {
166
+ try {
167
+ await node_fs_1.promises.unlink(tmp);
168
+ }
169
+ catch {
170
+ /* ignore */
171
+ }
172
+ throw new conditional_write_js_1.StaleVersionTokenAbort(still);
173
+ }
174
+ // Atomic replace on same filesystem (POSIX rename; Windows overwrite where supported).
175
+ await node_fs_1.promises.rename(tmp, target);
176
+ }
177
+ catch (err) {
178
+ if (err instanceof conditional_write_js_1.StaleVersionTokenAbort)
179
+ throw err;
180
+ // Best-effort cleanup of temp — never leave partial target from failed rename.
181
+ try {
182
+ await node_fs_1.promises.unlink(tmp);
183
+ }
184
+ catch {
185
+ /* ignore */
186
+ }
187
+ throw err;
188
+ }
189
+ return { path: target, bytes: body.length, written_content_hash: writtenHash };
190
+ },
191
+ });
192
+ }
193
+ /**
194
+ * Opt-in PriorContentResolver that reads a file path from tool arguments.
195
+ * Returns file utf8 content for freshness measurement (string only — tokens travel separately
196
+ * via versioned_content / conditioned_on_token on the call context).
197
+ *
198
+ * Plug-in: pass as GuardConfig.resolvePriorContent / withCodeRifts({ resolvePriorContent }).
199
+ */
200
+ function createFsPriorContentResolver(options) {
201
+ const pathForArtifact = options?.pathForArtifact;
202
+ return async (req) => {
203
+ let filePath = typeof req.path === 'string' && req.path.length > 0 ? req.path : undefined;
204
+ if (!filePath && pathForArtifact) {
205
+ const mapped = pathForArtifact(req.artifactId);
206
+ if (typeof mapped === 'string' && mapped.length > 0)
207
+ filePath = mapped;
208
+ }
209
+ if (!filePath)
210
+ return null;
211
+ try {
212
+ return await node_fs_1.promises.readFile(filePath, 'utf8');
213
+ }
214
+ catch (err) {
215
+ const code = err && typeof err === 'object' && 'code' in err
216
+ ? String(err.code)
217
+ : '';
218
+ if (code === 'ENOENT')
219
+ return null;
220
+ throw err;
221
+ }
222
+ };
223
+ }
224
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../src/cas-adapters/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6Bb,gDAQC;AAOD,oDAmBC;AAMD,8CAOC;AA0BD,oDAwDC;AASD,oEA0BC;AA/LD,6CAAsD;AACtD,qCAA0C;AAC1C,gDAAkC;AAClC,kEAOiC;AAwLxB,4FA5LP,kCAAW,OA4LO;AArLpB,mFAAmF;AACtE,QAAA,uBAAuB,GAAG,QAAQ,CAAC;AAEhD;;;GAGG;AACU,QAAA,eAAe,GAAiB,cAAc,CAAC;AAE5D,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,mFAAmF;AACnF,SAAgB,kBAAkB,CAAC,KAAsC;IACvE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,+BAAuB,CAAC;QAAE,OAAO,IAAI,CAAC;IACzF,IAAI,KAAK,KAAK,uBAAe;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,+BAAuB,CAAC,MAAM,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACnC,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,oBAAoB,CAAC,QAAgB;IACzD,IAAI,EAAE,CAAC;IACP,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,kBAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG;YAC1D,CAAC,CAAC,MAAM,CAAE,GAAyB,CAAC,IAAI,CAAC;YACzC,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,uBAAe,CAAC;QAC9C,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC;QACjB,uEAAuE;QACvE,MAAM,IAAI,KAAK,CAAC,6CAA6C,QAAQ,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,kBAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,GAAG,+BAAuB,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;AACxD,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,iBAAiB,CAAC,QAAgB;IACtD,MAAM,aAAa,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC3D,IAAI,aAAa,KAAK,uBAAe,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC;IACxC,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,kBAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;AACpC,CAAC;AAUD;;;;;;;;;;;;;;;GAeG;AACI,KAAK,UAAU,oBAAoB,CACxC,IAA8B;IAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;IACjG,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAEpC,OAAO,IAAA,yCAAkB,EAAC;QACxB,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,aAAa,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,MAAM,CAAC;QACjD,0BAA0B,EAAE,IAAI;QAChC,uFAAuF;QACvF,qBAAqB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACtC,8FAA8F;YAC9F,yFAAyF;YACzF,0FAA0F;YAC1F,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,QAAQ,KAAK,MAAM,CAAC,oBAAoB;gBAAE,OAAO,IAAI,CAAC;YAC1D,uEAAuE;YACvE,OAAO,GAAG,+BAAuB,gCAAgC,CAAC;QACpE,CAAC;QACD,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,kBAAG,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CACnB,GAAG,EACH,kBAAkB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,IAAI,IAAA,yBAAW,EAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAC/F,CAAC;YACF,IAAI,CAAC;gBACH,MAAM,kBAAG,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC/B,+FAA+F;gBAC/F,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,CAAC;gBACjD,IAAI,CAAC,IAAA,kCAAW,EAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC;oBAC7C,IAAI,CAAC;wBACH,MAAM,kBAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBACxB,CAAC;oBAAC,MAAM,CAAC;wBACP,YAAY;oBACd,CAAC;oBACD,MAAM,IAAI,6CAAsB,CAAC,KAAK,CAAC,CAAC;gBAC1C,CAAC;gBACD,uFAAuF;gBACvF,MAAM,kBAAG,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,6CAAsB;oBAAE,MAAM,GAAG,CAAC;gBACrD,+EAA+E;gBAC/E,IAAI,CAAC;oBACH,MAAM,kBAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACxB,CAAC;gBAAC,MAAM,CAAC;oBACP,YAAY;gBACd,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC;QACjF,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,4BAA4B,CAAC,OAM5C;IACC,MAAM,eAAe,GAAG,OAAO,EAAE,eAAe,CAAC;IACjD,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,IAAI,QAAQ,GACV,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7E,IAAI,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC/C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,QAAQ,GAAG,MAAM,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,MAAM,kBAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG;gBAC1D,CAAC,CAAC,MAAM,CAAE,GAAyB,CAAC,IAAI,CAAC;gBACzC,CAAC,CAAC,EAAE,CAAC;YACP,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YACnC,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Registry compareAndSwap CAS adapter — opaque registry/version token discipline over host-injected I/O.
3
+ *
4
+ * Uses executeIfUnchanged (conditional-write.ts). Does not invent a parallel outcome shape.
5
+ * Token format is opaque to the guard (string equality only).
6
+ *
7
+ * Token encoding (this adapter only; not interpreted by the core):
8
+ * registry:v1:<host_registry_token>
9
+ * Missing / empty token → REGISTRY_ABSENT_TOKEN.
10
+ *
11
+ * HONESTY: this adapter never talks to a registry client. The host callback performs
12
+ * compareAndSwap(expected, newValue) (or equivalent) and reports {swapped|conflict}.
13
+ * The adapter only normalizes tokens and maps the report onto ExecuteIfUnchangedOutcome.
14
+ *
15
+ * No registry SDKs — all I/O is host-injected.
16
+ */
17
+ import { tokensEqual, type ExecuteIfUnchangedOutcome, type VersionToken } from '../conditional-write.js';
18
+ /** Prefix for this adapter's opaque tokens (equality-only outside this module). */
19
+ export declare const REGISTRY_VERSION_TOKEN_PREFIX = "registry:v1:";
20
+ /**
21
+ * Token used when the registry key is absent / unversioned.
22
+ * Hosts that measured absence should pass this as expected_token for first put.
23
+ */
24
+ export declare const REGISTRY_ABSENT_TOKEN: VersionToken;
25
+ /**
26
+ * Build a VersionToken from a host registry revision / generation / etag-like value.
27
+ * null / undefined / empty → REGISTRY_ABSENT_TOKEN.
28
+ */
29
+ export declare function createRegistryVersionToken(token: string | number | bigint | null | undefined): VersionToken;
30
+ /** Raw value embedded in a registry:v1: token (for host CAS APIs). Absent → null. */
31
+ export declare function registryTokenRaw(token: VersionToken | null | undefined): string | null;
32
+ /**
33
+ * Host report after compareAndSwap (or equivalent).
34
+ */
35
+ export type RegistryHostCasReport<T = unknown> = {
36
+ swapped: true;
37
+ /** New registry token after successful swap; null/omit when unknown. */
38
+ new_token?: string | number | bigint | null;
39
+ result?: T;
40
+ } | {
41
+ swapped: false;
42
+ /** Current token if observed on conflict; omit → null (no invented token). */
43
+ current_token?: string | number | bigint | null;
44
+ } | {
45
+ status: 'committed';
46
+ new_token?: string | number | bigint | null;
47
+ result?: T;
48
+ } | {
49
+ status: 'conflict';
50
+ current_token?: string | number | bigint | null;
51
+ };
52
+ export type WriteRegistryIfUnchangedArgs<T = unknown> = {
53
+ /** Token measured before the host decided to write (from createRegistryVersionToken). */
54
+ expected_token: VersionToken;
55
+ /** Re-read the registry key's current token. Pre-write and post-write when detect is on. */
56
+ current_token: () => string | number | bigint | null | Promise<string | number | bigint | null>;
57
+ /**
58
+ * Host compareAndSwap. Receives the raw expected token for the CAS call.
59
+ * Adapter does not invoke any registry client.
60
+ */
61
+ compareAndSwap: (ctx: {
62
+ expected: string | null;
63
+ expected_token: VersionToken;
64
+ }) => RegistryHostCasReport<T> | Promise<RegistryHostCasReport<T>>;
65
+ /**
66
+ * Opt-in post-commit detection (default false).
67
+ * When host omits new_token on success, detection is a no-op.
68
+ */
69
+ detect_stale_during_commit?: boolean;
70
+ };
71
+ export type RegistryWriteResult<T = unknown> = {
72
+ new_token: string | null;
73
+ result: T | undefined;
74
+ };
75
+ /**
76
+ * Conditional registry write: re-read token; if matches → host compareAndSwap.
77
+ *
78
+ * Mapping (host report → ExecuteIfUnchangedOutcome):
79
+ * swapped:true / status:committed → committed
80
+ * swapped:false / status:conflict → refused / stale_version_token
81
+ * current_token from host when supplied, else null
82
+ *
83
+ * Wired through executeIfUnchanged — not a parallel path.
84
+ */
85
+ export declare function writeRegistryIfUnchanged<T = unknown>(args: WriteRegistryIfUnchangedArgs<T>): Promise<ExecuteIfUnchangedOutcome<RegistryWriteResult<T>>>;
86
+ /** Re-export equality helper for hosts comparing tokens without importing core module. */
87
+ export { tokensEqual };
88
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/cas-adapters/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAGL,WAAW,EACX,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EAClB,MAAM,yBAAyB,CAAC;AAEjC,mFAAmF;AACnF,eAAO,MAAM,6BAA6B,iBAAiB,CAAC;AAE5D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAAmC,CAAC;AAExE;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACjD,YAAY,CAMd;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAOtF;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,GAAG,OAAO,IACzC;IACE,OAAO,EAAE,IAAI,CAAC;IACd,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,CAAC,CAAC;CACZ,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACjD,GACD;IACE,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,CAAC,CAAC;CACZ,GACD;IACE,MAAM,EAAE,UAAU,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACjD,CAAC;AAEN,MAAM,MAAM,4BAA4B,CAAC,CAAC,GAAG,OAAO,IAAI;IACtD,yFAAyF;IACzF,cAAc,EAAE,YAAY,CAAC;IAC7B,4FAA4F;IAC5F,aAAa,EAAE,MACX,MAAM,GACN,MAAM,GACN,MAAM,GACN,IAAI,GACJ,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C;;;OAGG;IACH,cAAc,EAAE,CAAC,GAAG,EAAE;QACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,cAAc,EAAE,YAAY,CAAC;KAC9B,KAAK,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE;;;OAGG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC;CACvB,CAAC;AA0BF;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,GAAG,OAAO,EACxD,IAAI,EAAE,4BAA4B,CAAC,CAAC,CAAC,GACpC,OAAO,CAAC,yBAAyB,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAsC5D;AAED,0FAA0F;AAC1F,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Registry compareAndSwap CAS adapter — opaque registry/version token discipline over host-injected I/O.
3
+ *
4
+ * Uses executeIfUnchanged (conditional-write.ts). Does not invent a parallel outcome shape.
5
+ * Token format is opaque to the guard (string equality only).
6
+ *
7
+ * Token encoding (this adapter only; not interpreted by the core):
8
+ * registry:v1:<host_registry_token>
9
+ * Missing / empty token → REGISTRY_ABSENT_TOKEN.
10
+ *
11
+ * HONESTY: this adapter never talks to a registry client. The host callback performs
12
+ * compareAndSwap(expected, newValue) (or equivalent) and reports {swapped|conflict}.
13
+ * The adapter only normalizes tokens and maps the report onto ExecuteIfUnchangedOutcome.
14
+ *
15
+ * No registry SDKs — all I/O is host-injected.
16
+ */
17
+ 'use strict';
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.tokensEqual = exports.REGISTRY_ABSENT_TOKEN = exports.REGISTRY_VERSION_TOKEN_PREFIX = void 0;
20
+ exports.createRegistryVersionToken = createRegistryVersionToken;
21
+ exports.registryTokenRaw = registryTokenRaw;
22
+ exports.writeRegistryIfUnchanged = writeRegistryIfUnchanged;
23
+ const conditional_write_js_1 = require("../conditional-write.js");
24
+ Object.defineProperty(exports, "tokensEqual", { enumerable: true, get: function () { return conditional_write_js_1.tokensEqual; } });
25
+ /** Prefix for this adapter's opaque tokens (equality-only outside this module). */
26
+ exports.REGISTRY_VERSION_TOKEN_PREFIX = 'registry:v1:';
27
+ /**
28
+ * Token used when the registry key is absent / unversioned.
29
+ * Hosts that measured absence should pass this as expected_token for first put.
30
+ */
31
+ exports.REGISTRY_ABSENT_TOKEN = 'registry:v1:absent';
32
+ /**
33
+ * Build a VersionToken from a host registry revision / generation / etag-like value.
34
+ * null / undefined / empty → REGISTRY_ABSENT_TOKEN.
35
+ */
36
+ function createRegistryVersionToken(token) {
37
+ if (token == null)
38
+ return exports.REGISTRY_ABSENT_TOKEN;
39
+ if (typeof token === 'number' && !Number.isFinite(token))
40
+ return exports.REGISTRY_ABSENT_TOKEN;
41
+ const s = String(token).trim();
42
+ if (s.length === 0)
43
+ return exports.REGISTRY_ABSENT_TOKEN;
44
+ return `${exports.REGISTRY_VERSION_TOKEN_PREFIX}${s}`;
45
+ }
46
+ /** Raw value embedded in a registry:v1: token (for host CAS APIs). Absent → null. */
47
+ function registryTokenRaw(token) {
48
+ if (typeof token !== 'string' || !token.startsWith(exports.REGISTRY_VERSION_TOKEN_PREFIX)) {
49
+ return null;
50
+ }
51
+ if (token === exports.REGISTRY_ABSENT_TOKEN)
52
+ return null;
53
+ const raw = token.slice(exports.REGISTRY_VERSION_TOKEN_PREFIX.length);
54
+ return raw.length > 0 ? raw : null;
55
+ }
56
+ function normalizeRegistryReport(report) {
57
+ if (!report || typeof report !== 'object') {
58
+ throw new Error('writeRegistryIfUnchanged: host compareAndSwap must return RegistryHostCasReport');
59
+ }
60
+ if ('swapped' in report) {
61
+ if (report.swapped === true) {
62
+ return { kind: 'committed', new_token: report.new_token, result: report.result };
63
+ }
64
+ return { kind: 'conflict', current_token: report.current_token };
65
+ }
66
+ if (report.status === 'committed') {
67
+ return { kind: 'committed', new_token: report.new_token, result: report.result };
68
+ }
69
+ if (report.status === 'conflict') {
70
+ return { kind: 'conflict', current_token: report.current_token };
71
+ }
72
+ throw new Error('writeRegistryIfUnchanged: unknown host report shape');
73
+ }
74
+ /**
75
+ * Conditional registry write: re-read token; if matches → host compareAndSwap.
76
+ *
77
+ * Mapping (host report → ExecuteIfUnchangedOutcome):
78
+ * swapped:true / status:committed → committed
79
+ * swapped:false / status:conflict → refused / stale_version_token
80
+ * current_token from host when supplied, else null
81
+ *
82
+ * Wired through executeIfUnchanged — not a parallel path.
83
+ */
84
+ async function writeRegistryIfUnchanged(args) {
85
+ const detect = args.detect_stale_during_commit === true;
86
+ return (0, conditional_write_js_1.executeIfUnchanged)({
87
+ expected_token: args.expected_token,
88
+ current_token: async () => createRegistryVersionToken(await args.current_token()),
89
+ detect_stale_during_commit: detect,
90
+ expected_after_commit: detect
91
+ ? async (written) => {
92
+ if (typeof written.new_token === 'string' && written.new_token.trim().length > 0) {
93
+ return createRegistryVersionToken(written.new_token);
94
+ }
95
+ return createRegistryVersionToken(await args.current_token());
96
+ }
97
+ : undefined,
98
+ write: async () => {
99
+ const report = await args.compareAndSwap({
100
+ expected: registryTokenRaw(args.expected_token),
101
+ expected_token: args.expected_token,
102
+ });
103
+ const norm = normalizeRegistryReport(report);
104
+ if (norm.kind === 'conflict') {
105
+ const cur = norm.current_token !== undefined
106
+ ? createRegistryVersionToken(norm.current_token)
107
+ : null;
108
+ throw new conditional_write_js_1.StaleVersionTokenAbort(cur);
109
+ }
110
+ const new_token = norm.new_token === undefined || norm.new_token === null
111
+ ? null
112
+ : String(norm.new_token);
113
+ return {
114
+ new_token,
115
+ result: norm.result,
116
+ };
117
+ },
118
+ });
119
+ }
120
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/cas-adapters/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * CAS attestation binder (ID781 option A follow-on) — separate record linking a frozen
3
+ * GuardExecutionProof (v1) with an ExecuteIfUnchangedOutcome.
4
+ *
5
+ * Does NOT modify execution-proof.ts, the proof shape, or conditional-write outcome types.
6
+ * Does NOT claim that the host write is unique, that version tokens equal change_fp, or that
7
+ * committed_stale_detected is "safe". Those non-claims are always set on `limits`.
8
+ *
9
+ * The proof's own limit `conditional_write_is_host_asserted_not_cas_verified` names this gap;
10
+ * this module is the separate attestation surface that pairs proof + CAS outcome without
11
+ * widening the proof spec.
12
+ */
13
+ import type { GuardExecutionProof, ExecutionResultHash } from './execution-proof.js';
14
+ import type { ExecuteIfUnchangedOutcome, VersionToken } from './conditional-write.js';
15
+ /** Machine-readable schema id — mirrors EXECUTION_PROOF_SPEC style. */
16
+ export declare const CAS_ATTESTATION_SPEC: "cas-attestation.v1";
17
+ /**
18
+ * Explicit non-claims. Always set (same discipline as GuardExecutionProof.limits).
19
+ * Readers that treat missing fields as "ok" are wrong.
20
+ */
21
+ export type CasAttestationLimits = {
22
+ /** Host may have performed other writes outside executeIfUnchanged. */
23
+ does_not_claim_only_write_on_host: true;
24
+ /** version_token / post_commit_token are opaque CAS resource versions — not change_fp identity. */
25
+ does_not_claim_version_token_proves_change_fp_match: true;
26
+ /** committed_stale_detected means write ran and post-check disagreed — not "safe" or rolled back. */
27
+ does_not_claim_committed_stale_is_safe: true;
28
+ /** execution_result_hash hashes the factory return, not CAS file bytes / token equality. */
29
+ does_not_claim_execution_result_hash_equals_cas_bytes: true;
30
+ /** Same host-bypass residual as the proof family — package cannot force host CAS use. */
31
+ does_not_claim_host_cannot_bypass: true;
32
+ /** Attestation is linkage of two inputs, not a re-decision of governance ALLOW/BLOCK. */
33
+ does_not_claim_governance_redecision: true;
34
+ };
35
+ /** CAS branch projection — only fields present on the measured outcome branch. */
36
+ export type CasAttestationCas = {
37
+ status: 'committed';
38
+ write_ran: true;
39
+ version_token: VersionToken;
40
+ } | {
41
+ status: 'refused';
42
+ write_ran: false;
43
+ reason: 'stale_version_token';
44
+ expected_token: VersionToken;
45
+ current_token: VersionToken | null;
46
+ } | {
47
+ status: 'committed_stale_detected';
48
+ write_ran: true;
49
+ reason: 'stale_during_commit';
50
+ expected_token: VersionToken;
51
+ post_commit_token: VersionToken | null;
52
+ };
53
+ /**
54
+ * Frozen cas-attestation.v1 record.
55
+ * References are lifted from the proof; cas is projected from the outcome; derived flags
56
+ * are only what is honestly computable from those two inputs.
57
+ */
58
+ export type CasAttestation = {
59
+ attestation_spec: typeof CAS_ATTESTATION_SPEC;
60
+ references: {
61
+ decision_id: string | null;
62
+ change_fp: string | null;
63
+ operation: string | null;
64
+ execution_result_hash: ExecutionResultHash;
65
+ receipt_verified: boolean;
66
+ };
67
+ cas: CasAttestationCas;
68
+ derived: {
69
+ /**
70
+ * receipt.verified === true AND outcome.status === 'committed'
71
+ * (clean commit only — committed_stale_detected is NOT this flag).
72
+ */
73
+ authorized_and_committed: boolean;
74
+ /** Write mutation ran: committed or committed_stale_detected. */
75
+ write_ran: boolean;
76
+ /** outcome.status === 'committed_stale_detected'. */
77
+ stale_during_commit: boolean;
78
+ /** outcome.status === 'refused'. */
79
+ refused: boolean;
80
+ };
81
+ limits: CasAttestationLimits;
82
+ };
83
+ /** Type guard: object carries the frozen v1 proof_spec. */
84
+ export declare function isGuardExecutionProof(x: unknown): x is GuardExecutionProof;
85
+ /** Type guard: object is one of the three ExecuteIfUnchangedOutcome branches. */
86
+ export declare function isExecuteIfUnchangedOutcome(x: unknown): x is ExecuteIfUnchangedOutcome<unknown>;
87
+ /**
88
+ * Bind a frozen GuardExecutionProof with an ExecuteIfUnchangedOutcome into a cas-attestation.v1.
89
+ *
90
+ * Validation-first: rejects non-v1 proofs and non-outcome shapes (throws TypeError —
91
+ * builders fail closed; the human render layer soft-fails instead).
92
+ */
93
+ export declare function buildCasAttestation(proof: GuardExecutionProof, outcome: ExecuteIfUnchangedOutcome<unknown>): CasAttestation;
94
+ //# sourceMappingURL=cas-attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cas-attestation.d.ts","sourceRoot":"","sources":["../../src/cas-attestation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAErF,OAAO,KAAK,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtF,uEAAuE;AACvE,eAAO,MAAM,oBAAoB,EAAG,oBAA6B,CAAC;AAElE;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,uEAAuE;IACvE,iCAAiC,EAAE,IAAI,CAAC;IACxC,mGAAmG;IACnG,mDAAmD,EAAE,IAAI,CAAC;IAC1D,qGAAqG;IACrG,sCAAsC,EAAE,IAAI,CAAC;IAC7C,4FAA4F;IAC5F,qDAAqD,EAAE,IAAI,CAAC;IAC5D,yFAAyF;IACzF,iCAAiC,EAAE,IAAI,CAAC;IACxC,yFAAyF;IACzF,oCAAoC,EAAE,IAAI,CAAC;CAC5C,CAAC;AAWF,kFAAkF;AAClF,MAAM,MAAM,iBAAiB,GACzB;IACE,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,aAAa,EAAE,YAAY,CAAC;CAC7B,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,cAAc,EAAE,YAAY,CAAC;IAC7B,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;CACpC,GACD;IACE,MAAM,EAAE,0BAA0B,CAAC;IACnC,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,cAAc,EAAE,YAAY,CAAC;IAC7B,iBAAiB,EAAE,YAAY,GAAG,IAAI,CAAC;CACxC,CAAC;AAEN;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,gBAAgB,EAAE,OAAO,oBAAoB,CAAC;IAC9C,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,qBAAqB,EAAE,mBAAmB,CAAC;QAC3C,gBAAgB,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,GAAG,EAAE,iBAAiB,CAAC;IACvB,OAAO,EAAE;QACP;;;WAGG;QACH,wBAAwB,EAAE,OAAO,CAAC;QAClC,iEAAiE;QACjE,SAAS,EAAE,OAAO,CAAC;QACnB,qDAAqD;QACrD,mBAAmB,EAAE,OAAO,CAAC;QAC7B,oCAAoC;QACpC,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,MAAM,EAAE,oBAAoB,CAAC;CAC9B,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,mBAAmB,CAQ1E;AAED,iFAAiF;AACjF,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,yBAAyB,CAAC,OAAO,CAAC,CAgB/F;AAiCD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,yBAAyB,CAAC,OAAO,CAAC,GAC1C,cAAc,CAyChB"}