@rexezuge/tooling 0.0.0-stage → 1.0.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 (160) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +297 -2
  3. package/dist/eslint.d.ts +120 -0
  4. package/dist/eslint.d.ts.map +1 -0
  5. package/dist/eslint.js +551 -0
  6. package/dist/eslint.js.map +1 -0
  7. package/dist/functions/pages-proxy.d.ts +113 -0
  8. package/dist/functions/pages-proxy.d.ts.map +1 -0
  9. package/dist/functions/pages-proxy.js +131 -0
  10. package/dist/functions/pages-proxy.js.map +1 -0
  11. package/dist/index.d.ts +31 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +28 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/scripts/backup/d1-target.d.ts +35 -0
  16. package/dist/scripts/backup/d1-target.d.ts.map +1 -0
  17. package/dist/scripts/backup/d1-target.js +31 -0
  18. package/dist/scripts/backup/d1-target.js.map +1 -0
  19. package/dist/scripts/backup/destination-config.d.ts +61 -0
  20. package/dist/scripts/backup/destination-config.d.ts.map +1 -0
  21. package/dist/scripts/backup/destination-config.js +57 -0
  22. package/dist/scripts/backup/destination-config.js.map +1 -0
  23. package/dist/scripts/backup/encrypt-backup.d.ts +35 -0
  24. package/dist/scripts/backup/encrypt-backup.d.ts.map +1 -0
  25. package/dist/scripts/backup/encrypt-backup.js +98 -0
  26. package/dist/scripts/backup/encrypt-backup.js.map +1 -0
  27. package/dist/scripts/backup/naming.d.ts +44 -0
  28. package/dist/scripts/backup/naming.d.ts.map +1 -0
  29. package/dist/scripts/backup/naming.js +58 -0
  30. package/dist/scripts/backup/naming.js.map +1 -0
  31. package/dist/scripts/check-god-files.d.ts +164 -0
  32. package/dist/scripts/check-god-files.d.ts.map +1 -0
  33. package/dist/scripts/check-god-files.js +271 -0
  34. package/dist/scripts/check-god-files.js.map +1 -0
  35. package/dist/scripts/ensure-spa-shell-stub.d.ts +3 -0
  36. package/dist/scripts/ensure-spa-shell-stub.d.ts.map +1 -0
  37. package/dist/scripts/ensure-spa-shell-stub.js +30 -0
  38. package/dist/scripts/ensure-spa-shell-stub.js.map +1 -0
  39. package/dist/scripts/init-secrets.d.ts +63 -0
  40. package/dist/scripts/init-secrets.d.ts.map +1 -0
  41. package/dist/scripts/init-secrets.js +240 -0
  42. package/dist/scripts/init-secrets.js.map +1 -0
  43. package/dist/scripts/lib/cli-args.d.ts +78 -0
  44. package/dist/scripts/lib/cli-args.d.ts.map +1 -0
  45. package/dist/scripts/lib/cli-args.js +116 -0
  46. package/dist/scripts/lib/cli-args.js.map +1 -0
  47. package/dist/scripts/lib/github-actions.d.ts +26 -0
  48. package/dist/scripts/lib/github-actions.d.ts.map +1 -0
  49. package/dist/scripts/lib/github-actions.js +38 -0
  50. package/dist/scripts/lib/github-actions.js.map +1 -0
  51. package/dist/scripts/lib/wrangler-table.d.ts +46 -0
  52. package/dist/scripts/lib/wrangler-table.d.ts.map +1 -0
  53. package/dist/scripts/lib/wrangler-table.js +99 -0
  54. package/dist/scripts/lib/wrangler-table.js.map +1 -0
  55. package/dist/scripts/migrations-lock.d.ts +3 -0
  56. package/dist/scripts/migrations-lock.d.ts.map +1 -0
  57. package/dist/scripts/migrations-lock.js +46 -0
  58. package/dist/scripts/migrations-lock.js.map +1 -0
  59. package/dist/scripts/prepare-wrangler-config.d.ts +3 -0
  60. package/dist/scripts/prepare-wrangler-config.d.ts.map +1 -0
  61. package/dist/scripts/prepare-wrangler-config.js +50 -0
  62. package/dist/scripts/prepare-wrangler-config.js.map +1 -0
  63. package/dist/scripts/spa-shell.d.ts +41 -0
  64. package/dist/scripts/spa-shell.d.ts.map +1 -0
  65. package/dist/scripts/spa-shell.js +155 -0
  66. package/dist/scripts/spa-shell.js.map +1 -0
  67. package/dist/scripts/validate-locales.d.ts +26 -0
  68. package/dist/scripts/validate-locales.d.ts.map +1 -0
  69. package/dist/scripts/validate-locales.js +350 -0
  70. package/dist/scripts/validate-locales.js.map +1 -0
  71. package/dist/scripts/verify-migrations.d.ts +62 -0
  72. package/dist/scripts/verify-migrations.d.ts.map +1 -0
  73. package/dist/scripts/verify-migrations.js +302 -0
  74. package/dist/scripts/verify-migrations.js.map +1 -0
  75. package/dist/scripts/verify-spa-shell.d.ts +3 -0
  76. package/dist/scripts/verify-spa-shell.d.ts.map +1 -0
  77. package/dist/scripts/verify-spa-shell.js +53 -0
  78. package/dist/scripts/verify-spa-shell.js.map +1 -0
  79. package/dist/scripts/wrangler-config/cli.d.ts +22 -0
  80. package/dist/scripts/wrangler-config/cli.d.ts.map +1 -0
  81. package/dist/scripts/wrangler-config/cli.js +51 -0
  82. package/dist/scripts/wrangler-config/cli.js.map +1 -0
  83. package/dist/scripts/wrangler-config/patches.d.ts +51 -0
  84. package/dist/scripts/wrangler-config/patches.d.ts.map +1 -0
  85. package/dist/scripts/wrangler-config/patches.js +140 -0
  86. package/dist/scripts/wrangler-config/patches.js.map +1 -0
  87. package/dist/scripts/wrangler-config/resources.d.ts +70 -0
  88. package/dist/scripts/wrangler-config/resources.d.ts.map +1 -0
  89. package/dist/scripts/wrangler-config/resources.js +290 -0
  90. package/dist/scripts/wrangler-config/resources.js.map +1 -0
  91. package/dist/scripts/wrangler-config/types.d.ts +103 -0
  92. package/dist/scripts/wrangler-config/types.d.ts.map +1 -0
  93. package/dist/scripts/wrangler-config/types.js +49 -0
  94. package/dist/scripts/wrangler-config/types.js.map +1 -0
  95. package/dist/test/integration-migrations.d.ts +167 -0
  96. package/dist/test/integration-migrations.d.ts.map +1 -0
  97. package/dist/test/integration-migrations.js +171 -0
  98. package/dist/test/integration-migrations.js.map +1 -0
  99. package/dist/test/mocks/cloudflare-workers.d.ts +106 -0
  100. package/dist/test/mocks/cloudflare-workers.d.ts.map +1 -0
  101. package/dist/test/mocks/cloudflare-workers.js +90 -0
  102. package/dist/test/mocks/cloudflare-workers.js.map +1 -0
  103. package/dist/vite.d.ts +117 -0
  104. package/dist/vite.d.ts.map +1 -0
  105. package/dist/vite.js +125 -0
  106. package/dist/vite.js.map +1 -0
  107. package/dist/vitest-web.d.ts +73 -0
  108. package/dist/vitest-web.d.ts.map +1 -0
  109. package/dist/vitest-web.js +72 -0
  110. package/dist/vitest-web.js.map +1 -0
  111. package/dist/vitest.d.ts +92 -0
  112. package/dist/vitest.d.ts.map +1 -0
  113. package/dist/vitest.js +128 -0
  114. package/dist/vitest.js.map +1 -0
  115. package/package.json +58 -3
  116. package/src/eslint.test.ts +175 -0
  117. package/src/eslint.ts +640 -0
  118. package/src/functions/pages-proxy.test.ts +72 -0
  119. package/src/functions/pages-proxy.ts +187 -0
  120. package/src/github/actions/retry-step/action.yml +39 -0
  121. package/src/github/actions/setup-env/action.yml +20 -0
  122. package/src/github/dependabot.yml +30 -0
  123. package/src/github/workflows/backup-main.yml +46 -0
  124. package/src/github/workflows/continuous-deployment.yml +188 -0
  125. package/src/github/workflows/continuous-integration.yml +259 -0
  126. package/src/github/workflows/scheduled-version-update.yml +38 -0
  127. package/src/github/workflows/upstream-sync.yml +56 -0
  128. package/src/index.ts +42 -0
  129. package/src/scripts/backup/backup-rules.test.ts +105 -0
  130. package/src/scripts/backup/d1-target.ts +54 -0
  131. package/src/scripts/backup/destination-config.ts +92 -0
  132. package/src/scripts/backup/encrypt-backup.ts +107 -0
  133. package/src/scripts/backup/naming.ts +62 -0
  134. package/src/scripts/check-god-files.test.ts +131 -0
  135. package/src/scripts/check-god-files.ts +327 -0
  136. package/src/scripts/ensure-spa-shell-stub.ts +34 -0
  137. package/src/scripts/init-secrets.ts +265 -0
  138. package/src/scripts/lib/cli-args.ts +154 -0
  139. package/src/scripts/lib/github-actions.ts +41 -0
  140. package/src/scripts/lib/wrangler-table.ts +105 -0
  141. package/src/scripts/migrations-lock.ts +52 -0
  142. package/src/scripts/prepare-wrangler-config.ts +51 -0
  143. package/src/scripts/spa-shell.test.ts +91 -0
  144. package/src/scripts/spa-shell.ts +179 -0
  145. package/src/scripts/validate-locales.test.ts +89 -0
  146. package/src/scripts/validate-locales.ts +380 -0
  147. package/src/scripts/verify-migrations.test.ts +71 -0
  148. package/src/scripts/verify-migrations.ts +364 -0
  149. package/src/scripts/verify-spa-shell.ts +56 -0
  150. package/src/scripts/wrangler-config/cli.ts +51 -0
  151. package/src/scripts/wrangler-config/patches.ts +157 -0
  152. package/src/scripts/wrangler-config/resources.ts +330 -0
  153. package/src/scripts/wrangler-config/types.ts +113 -0
  154. package/src/test/integration-migrations.test.ts +169 -0
  155. package/src/test/integration-migrations.ts +267 -0
  156. package/src/test/mocks/cloudflare-workers.ts +115 -0
  157. package/src/vite.test.ts +83 -0
  158. package/src/vite.ts +202 -0
  159. package/src/vitest-web.ts +109 -0
  160. package/src/vitest.ts +185 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Shared paths, placeholders and shape definitions for the wrangler config helpers.
3
+ *
4
+ * Provenance: ported from Edge-Sonic's `scripts/lib/wrangler-config/types.ts`.
5
+ * Every script that reads or writes `wrangler.jsonc` resolves it here, so the
6
+ * backup workflow cannot end up inspecting a different file than the deploy
7
+ * materialized.
8
+ *
9
+ * The paths default to `process.cwd()`, which is the repo root in every consumer:
10
+ * the scripts run as `pnpm exec tsx scripts/deploy/…` from there. `WRANGLER_CONFIG_PATH`
11
+ * / `WRANGLER_TEMPLATE_PATH` override them for a caller that is not in the repo
12
+ * root, which is the one case the cwd default gets wrong.
13
+ */
14
+ import path from 'node:path';
15
+ /** The config the deploy targets. */
16
+ export const CONFIG_PATH = process.env['WRANGLER_CONFIG_PATH'] ?? path.join(process.cwd(), 'wrangler.jsonc');
17
+ /** The committed template the config is materialized from. */
18
+ export const TEMPLATE_PATH = process.env['WRANGLER_TEMPLATE_PATH'] ?? path.join(process.cwd(), 'apps/api/wrangler.template.jsonc');
19
+ /**
20
+ * The id a template carries for a D1 database that does not exist yet.
21
+ *
22
+ * `provisionWranglerResources` replaces it with a real id; the backup scripts
23
+ * refuse to export while it is still in place, because a database that was just
24
+ * created holds no user data.
25
+ */
26
+ export const DEFAULT_UUID = '00000000-0000-0000-0000-000000000000';
27
+ /** The placeholder for a KV namespace id and for a Secrets Store id. */
28
+ export const DEFAULT_HEX_ID = '00000000000000000000000000000000';
29
+ /** The Secrets Store name a deployment uses. */
30
+ export const DEFAULT_SECRET_STORE_NAME = 'default';
31
+ /**
32
+ * Fallback when the config declares no `name`, used to derive resource names.
33
+ *
34
+ * Overridable per consumer with `WRANGLER_WORKER_NAME`, which keeps the default
35
+ * honest rather than baking one repo's name into the kit.
36
+ */
37
+ export const DEFAULT_WORKER_NAME = process.env['WRANGLER_WORKER_NAME'] ?? 'my-worker';
38
+ /**
39
+ * KV bindings a deployment always needs, and the namespace each maps to.
40
+ *
41
+ * A consumer whose worker has no cache binding passes an empty map; a consumer
42
+ * with one names it here or leaves the derived `<worker>-<BINDING>` convention.
43
+ */
44
+ export const DEFAULT_KV_NAMESPACE_NAMES = {
45
+ CACHE: `${DEFAULT_WORKER_NAME}-cache`,
46
+ };
47
+ /** Dimensions of a Vectorize index this kit provisions. */
48
+ export const VECTORIZE_DIMENSIONS = 1024;
49
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/scripts/wrangler-config/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,qCAAqC;AACrC,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAE7G,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kCAAkC,CAAC,CAAC;AAEnI;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAEnE,wEAAwE;AACxE,MAAM,CAAC,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAEjE,gDAAgD;AAChD,MAAM,CAAC,MAAM,yBAAyB,GAAG,SAAS,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,WAAW,CAAC;AAEtF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAA2B;IAChE,KAAK,EAAE,GAAG,mBAAmB,QAAQ;CACtC,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Applying the migration directory to a D1 binding — as a factory.
3
+ *
4
+ * Provenance: converged from `test/integration/helpers/migrations.ts` in six repos
5
+ * (AWS-AccessBridge, ChordDHT-Tracker, Durable-DAV, Durable-DAV-Router, Edge-Git,
6
+ * Mail-Meow) and `test/helpers/migrations.ts` in two more (CalDAV-Bridge,
7
+ * Edge-Sonic). All eight are the same file: a SQL splitter plus a range-addressed
8
+ * `applyMigrations`.
9
+ *
10
+ * ### Why it is a factory and not a module
11
+ *
12
+ * Every source file hardcodes where the migrations live, either as a
13
+ * `__INTEGRATION_MIGRATION_FILES__` binding injected by the Vitest config's
14
+ * `define`, or as a path derived from `import.meta.url`. The kit cannot know
15
+ * either, so the directory is an argument and the injection stays available as an
16
+ * option. One call to `createMigrationHelper({ migrationsDir })` gives the consumer
17
+ * the same helper their repo already has.
18
+ *
19
+ * ### What each source contributes
20
+ *
21
+ * - **Durable-DAV** — the trigger-aware splitter. `CREATE TRIGGER … BEGIN … END;`
22
+ * bodies contain semicolons that must not split, and a naive splitter produces
23
+ * statements SQLite rejects mid-migration. The BEGIN/END depth is tracked only
24
+ * outside strings and comments, and the word *before* `TRIGGER` disambiguates
25
+ * `CREATE TRIGGER` from a table called `trigger`. Durable-DAV also applies one
26
+ * file per `batch()` and names the offending statement in the error, which is
27
+ * the difference between "0007 failed" and a line number.
28
+ * - **AWS-AccessBridge** — the once-per-database guard. D1 records which
29
+ * migrations have run; this helper does the same, because `ALTER TABLE … ADD
30
+ * COLUMN` is not idempotent in SQLite and re-running the bundle fails with
31
+ * "duplicate column name". A `WeakMap` keyed on the binding is the right scope
32
+ * because each test file gets its own database. AWS also keeps `next` out of the
33
+ * line-comment branch, which never reads it, and preserves newlines inside block
34
+ * comments so an error's line numbers still point at the file.
35
+ * - **Edge-Sonic** — reading the directory off disk rather than a `define`
36
+ * binding, because a test that names one hardcoded file cannot tell **a new
37
+ * migration** from **an edit to an old one**, so it goes on passing through a
38
+ * schema change that never reached production.
39
+ *
40
+ * ### The splitter is not here
41
+ *
42
+ * The statement splitter — with all of Durable-DAV's trigger-aware rules and its
43
+ * comment-level history — lives once, in `@rexezuge/d1`. `@rexezuge/identity`'s
44
+ * migration applier delegates to the same module, so the splitter cannot drift
45
+ * between the suite helper and the production applier. The re-exports below keep
46
+ * this file's public surface identical to the source repos'.
47
+ *
48
+ * ### The lock is asserted, not reimplemented
49
+ *
50
+ * D1 records applied migrations by *filename*, so an applied migration is immutable
51
+ * in fact while being an ordinary text file in appearance. That fact lives in
52
+ * `migrations/migrations.lock.json`, and the rules that check it live once, in
53
+ * `scripts/verify-migrations.ts` — the same module the CI gate runs. This helper
54
+ * deliberately does not parse the lock itself: a second implementation of a thing
55
+ * already written is free to disagree with the first, and the two disagreeing would
56
+ * leave a suite green against a lock CI rejects.
57
+ *
58
+ * ### Generic over the binding
59
+ *
60
+ * `D1DatabaseLike` is structural — `prepare`, and `batch` when the runtime has it
61
+ * — so a fake D1 in a unit test, a real D1 in the workerd integration suite, and
62
+ * Miniflare's D1 all satisfy it without an import of `@cloudflare/workers-types`.
63
+ * `batch` is used when present (Durable-DAV's shape: one round trip per file, and
64
+ * the failure names the file) and a sequential `prepare().run()` loop otherwise
65
+ * (AWS's shape: works on a binding with no batch support).
66
+ */
67
+ import { executableStatements, splitSql } from '@rexezuge/d1';
68
+ /**
69
+ * One migration file, as it is read.
70
+ */
71
+ export interface MigrationFile {
72
+ /** Bare filename, e.g. `0007_replication.sql`. */
73
+ name: string;
74
+ /** The file's full text. */
75
+ sql: string;
76
+ }
77
+ /**
78
+ * The subset of a D1 prepared statement this helper uses.
79
+ */
80
+ export interface D1PreparedStatementLike {
81
+ run(): Promise<unknown>;
82
+ }
83
+ /**
84
+ * The subset of a D1 binding this helper uses.
85
+ *
86
+ * `batch` is optional because not every binding that can prepare a statement can
87
+ * batch one; where it exists it is the better path, and where it does not the
88
+ * sequential loop is equivalent for a migration whose statements are independent.
89
+ */
90
+ export interface D1DatabaseLike {
91
+ prepare(sql: string): D1PreparedStatementLike;
92
+ batch?(statements: readonly D1PreparedStatementLike[]): Promise<unknown>;
93
+ }
94
+ /**
95
+ * A closed range of migration files, by filename.
96
+ *
97
+ * Both ends inclusive, because "up to and including 0006" is the natural way to
98
+ * seed a pre-migration database and then apply the migration under test.
99
+ */
100
+ export interface MigrationRange {
101
+ from?: string;
102
+ to?: string;
103
+ }
104
+ /**
105
+ * What `createMigrationHelper` accepts.
106
+ */
107
+ export interface MigrationHelperOptions {
108
+ /**
109
+ * Directory holding the `.sql` files. Read top-level only, matching wrangler's
110
+ * default `${migrationsDir}/*.sql`, so the helper describes exactly the set
111
+ * wrangler will run.
112
+ */
113
+ readonly migrationsDir: string;
114
+ /**
115
+ * Migration files to use instead of reading `migrationsDir`.
116
+ *
117
+ * The escape hatch for a harness that embeds the SQL at build time. Same shape
118
+ * as the `__INTEGRATION_MIGRATION_FILES__` binding the source repos inject.
119
+ */
120
+ readonly files?: readonly MigrationFile[];
121
+ }
122
+ /**
123
+ * A bound migration helper.
124
+ */
125
+ export interface MigrationHelper {
126
+ /** Every migration, in apply order. */
127
+ migrationFiles(): MigrationFile[];
128
+ /** The filenames, in apply order. */
129
+ migrationFileNames(): string[];
130
+ /** The concatenation of every file, in apply order — what a fresh database becomes. */
131
+ migrationSql(): string;
132
+ /** One file's SQL, by name. "What does *this* file say", not "what does the set say". */
133
+ migrationSqlOf(name: string): string;
134
+ /** Split one file into statements, comments included. */
135
+ splitSql(sql: string): string[];
136
+ /** The statements of one file that SQLite will actually execute. */
137
+ executableStatements(sql: string): string[];
138
+ /**
139
+ * Apply a range of migrations, at most once per database and range.
140
+ *
141
+ * Per file rather than one batch for everything, so a test can stop between
142
+ * files: the identity-upgrade test needs to seed the *pre-0004* shape and then
143
+ * apply 0004 to it.
144
+ */
145
+ applyMigrations(db: D1DatabaseLike, range?: MigrationRange): Promise<void>;
146
+ }
147
+ /**
148
+ * Reads every `.sql` file in `dir`, in apply order.
149
+ *
150
+ * Sort is the filename sort D1 itself uses, rather than a numeric parse of the
151
+ * prefix: wrangler hands the directory to SQLite in lexicographic order, so a
152
+ * suite that reads it numerically disagrees with production on any prefix wider
153
+ * than four digits.
154
+ */
155
+ export declare function readMigrationFiles(dir: string): MigrationFile[];
156
+ /** Re-exported for surface parity with the source repos — the rules live in @rexezuge/d1. */
157
+ export { executableStatements, splitSql };
158
+ /**
159
+ * Bind a migration directory into a helper.
160
+ *
161
+ * ```ts
162
+ * const migrations = createMigrationHelper({ migrationsDir: path.join(REPO_ROOT, 'migrations') });
163
+ * await migrations.applyMigrations(env.DB);
164
+ * ```
165
+ */
166
+ export declare function createMigrationHelper(options: MigrationHelperOptions): MigrationHelper;
167
+ //# sourceMappingURL=integration-migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-migrations.d.ts","sourceRoot":"","sources":["../../src/test/integration-migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI9D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,CAAC;IAC9C,KAAK,CAAC,CAAC,UAAU,EAAE,SAAS,uBAAuB,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,cAAc,IAAI,aAAa,EAAE,CAAC;IAClC,qCAAqC;IACrC,kBAAkB,IAAI,MAAM,EAAE,CAAC;IAC/B,uFAAuF;IACvF,YAAY,IAAI,MAAM,CAAC;IACvB,yFAAyF;IACzF,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,oEAAoE;IACpE,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5C;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAM/D;AAeD,6FAA6F;AAC7F,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,CAAC;AAE1C;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAsEtF"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Applying the migration directory to a D1 binding — as a factory.
3
+ *
4
+ * Provenance: converged from `test/integration/helpers/migrations.ts` in six repos
5
+ * (AWS-AccessBridge, ChordDHT-Tracker, Durable-DAV, Durable-DAV-Router, Edge-Git,
6
+ * Mail-Meow) and `test/helpers/migrations.ts` in two more (CalDAV-Bridge,
7
+ * Edge-Sonic). All eight are the same file: a SQL splitter plus a range-addressed
8
+ * `applyMigrations`.
9
+ *
10
+ * ### Why it is a factory and not a module
11
+ *
12
+ * Every source file hardcodes where the migrations live, either as a
13
+ * `__INTEGRATION_MIGRATION_FILES__` binding injected by the Vitest config's
14
+ * `define`, or as a path derived from `import.meta.url`. The kit cannot know
15
+ * either, so the directory is an argument and the injection stays available as an
16
+ * option. One call to `createMigrationHelper({ migrationsDir })` gives the consumer
17
+ * the same helper their repo already has.
18
+ *
19
+ * ### What each source contributes
20
+ *
21
+ * - **Durable-DAV** — the trigger-aware splitter. `CREATE TRIGGER … BEGIN … END;`
22
+ * bodies contain semicolons that must not split, and a naive splitter produces
23
+ * statements SQLite rejects mid-migration. The BEGIN/END depth is tracked only
24
+ * outside strings and comments, and the word *before* `TRIGGER` disambiguates
25
+ * `CREATE TRIGGER` from a table called `trigger`. Durable-DAV also applies one
26
+ * file per `batch()` and names the offending statement in the error, which is
27
+ * the difference between "0007 failed" and a line number.
28
+ * - **AWS-AccessBridge** — the once-per-database guard. D1 records which
29
+ * migrations have run; this helper does the same, because `ALTER TABLE … ADD
30
+ * COLUMN` is not idempotent in SQLite and re-running the bundle fails with
31
+ * "duplicate column name". A `WeakMap` keyed on the binding is the right scope
32
+ * because each test file gets its own database. AWS also keeps `next` out of the
33
+ * line-comment branch, which never reads it, and preserves newlines inside block
34
+ * comments so an error's line numbers still point at the file.
35
+ * - **Edge-Sonic** — reading the directory off disk rather than a `define`
36
+ * binding, because a test that names one hardcoded file cannot tell **a new
37
+ * migration** from **an edit to an old one**, so it goes on passing through a
38
+ * schema change that never reached production.
39
+ *
40
+ * ### The splitter is not here
41
+ *
42
+ * The statement splitter — with all of Durable-DAV's trigger-aware rules and its
43
+ * comment-level history — lives once, in `@rexezuge/d1`. `@rexezuge/identity`'s
44
+ * migration applier delegates to the same module, so the splitter cannot drift
45
+ * between the suite helper and the production applier. The re-exports below keep
46
+ * this file's public surface identical to the source repos'.
47
+ *
48
+ * ### The lock is asserted, not reimplemented
49
+ *
50
+ * D1 records applied migrations by *filename*, so an applied migration is immutable
51
+ * in fact while being an ordinary text file in appearance. That fact lives in
52
+ * `migrations/migrations.lock.json`, and the rules that check it live once, in
53
+ * `scripts/verify-migrations.ts` — the same module the CI gate runs. This helper
54
+ * deliberately does not parse the lock itself: a second implementation of a thing
55
+ * already written is free to disagree with the first, and the two disagreeing would
56
+ * leave a suite green against a lock CI rejects.
57
+ *
58
+ * ### Generic over the binding
59
+ *
60
+ * `D1DatabaseLike` is structural — `prepare`, and `batch` when the runtime has it
61
+ * — so a fake D1 in a unit test, a real D1 in the workerd integration suite, and
62
+ * Miniflare's D1 all satisfy it without an import of `@cloudflare/workers-types`.
63
+ * `batch` is used when present (Durable-DAV's shape: one round trip per file, and
64
+ * the failure names the file) and a sequential `prepare().run()` loop otherwise
65
+ * (AWS's shape: works on a binding with no batch support).
66
+ */
67
+ import { executableStatements, splitSql } from '@rexezuge/d1';
68
+ import { readdirSync, readFileSync } from 'node:fs';
69
+ import { join } from 'node:path';
70
+ /**
71
+ * Reads every `.sql` file in `dir`, in apply order.
72
+ *
73
+ * Sort is the filename sort D1 itself uses, rather than a numeric parse of the
74
+ * prefix: wrangler hands the directory to SQLite in lexicographic order, so a
75
+ * suite that reads it numerically disagrees with production on any prefix wider
76
+ * than four digits.
77
+ */
78
+ export function readMigrationFiles(dir) {
79
+ const entries = readdirSync(dir, { withFileTypes: true });
80
+ return entries
81
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.sql'))
82
+ .map((entry) => ({ name: entry.name, sql: readFileSync(join(dir, entry.name), 'utf8') }))
83
+ .sort((left, right) => left.name.localeCompare(right.name));
84
+ }
85
+ /**
86
+ * Strip leading `--` and block comments, which the splitter folds into the
87
+ * statement it then reports on.
88
+ */
89
+ function stripLeadingComments(statement) {
90
+ let out = statement;
91
+ for (;;) {
92
+ const next = out.replace(/^\s*(?:--[^\n]*\n|\/\*[\s\S]*?\*\/)\s*/, '');
93
+ if (next === out)
94
+ return out.trim();
95
+ out = next;
96
+ }
97
+ }
98
+ /** Re-exported for surface parity with the source repos — the rules live in @rexezuge/d1. */
99
+ export { executableStatements, splitSql };
100
+ /**
101
+ * Bind a migration directory into a helper.
102
+ *
103
+ * ```ts
104
+ * const migrations = createMigrationHelper({ migrationsDir: path.join(REPO_ROOT, 'migrations') });
105
+ * await migrations.applyMigrations(env.DB);
106
+ * ```
107
+ */
108
+ export function createMigrationHelper(options) {
109
+ const files = options.files !== undefined ? [...options.files] : readMigrationFiles(options.migrationsDir);
110
+ /**
111
+ * Databases this helper has already migrated, keyed by the range applied.
112
+ *
113
+ * A `WeakMap` rather than a module-level `Set`, because the guard is per
114
+ * binding: two databases in one suite each need the bundle applied once, and a
115
+ * module-level set would silently skip the second.
116
+ */
117
+ const applied = new WeakMap();
118
+ const indexOf = (name, fallback) => {
119
+ if (name === undefined)
120
+ return fallback;
121
+ const found = files.findIndex((file) => file.name === name);
122
+ if (found === -1) {
123
+ throw new Error(`Unknown migration file: ${name}. Available: ${files.map((file) => file.name).join(', ')}`);
124
+ }
125
+ return found;
126
+ };
127
+ return {
128
+ migrationFiles: () => files.map((file) => ({ ...file })),
129
+ migrationFileNames: () => files.map((file) => file.name),
130
+ migrationSql: () => files.map((file) => file.sql).join('\n'),
131
+ migrationSqlOf: (name) => {
132
+ const file = files.find((candidate) => candidate.name === name);
133
+ if (file === undefined) {
134
+ throw new Error(`Unknown migration file: ${name}. Available: ${files.map((candidate) => candidate.name).join(', ')}`);
135
+ }
136
+ return file.sql;
137
+ },
138
+ splitSql,
139
+ executableStatements,
140
+ applyMigrations: async (db, range) => {
141
+ const start = indexOf(range?.from, 0);
142
+ const end = indexOf(range?.to, files.length - 1);
143
+ const key = `${start}:${end}`;
144
+ if (applied.get(db) === key)
145
+ return;
146
+ const applicable = files.slice(start, end + 1);
147
+ for (const file of applicable) {
148
+ const statements = executableStatements(file.sql);
149
+ if (statements.length === 0)
150
+ continue;
151
+ if (typeof db.batch === 'function') {
152
+ try {
153
+ await db.batch(statements.map((sql) => db.prepare(sql)));
154
+ }
155
+ catch (error) {
156
+ // A batch reports only the file's single failure, so name the statement:
157
+ // a migration error that says nothing about which of its nine statements
158
+ // broke is a migration error nobody fixes.
159
+ throw new Error(`${file.name}: batch of ${statements.length} statements failed at ${stripLeadingComments(statements.at(-1) ?? '').slice(0, 200)}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
160
+ }
161
+ continue;
162
+ }
163
+ for (const sql of statements) {
164
+ await db.prepare(sql).run();
165
+ }
166
+ }
167
+ applied.set(db, key);
168
+ },
169
+ };
170
+ }
171
+ //# sourceMappingURL=integration-migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-migrations.js","sourceRoot":"","sources":["../../src/test/integration-migrations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Stand-in for the `cloudflare:workers` module, which has no Node equivalent.
3
+ *
4
+ * Provenance: converged from the eight copies at `test/mocks/cloudflare-workers.ts`
5
+ * (AWS-AccessBridge, CalDAV-Bridge, ChordDHT-Tracker, Durable-DAV, Edge-Git,
6
+ * Edge-Sonic, Mail-Meow, Mail-Otter). All eight are the same twenty lines; the
7
+ * union is three base classes and the union exists because each repo discovered a
8
+ * missing one the hard way.
9
+ *
10
+ * ### What each source contributes
11
+ *
12
+ * - **DurableObject** — every copy. Stores `ctx` and `env` so a real DO class can
13
+ * be constructed and its lifecycle RPCs driven directly, without Miniflare.
14
+ * - **`RpcTarget`** — Durable-DAV's, and the reason is load-bearing rather than
15
+ * tidy: `dofs`' `Fs` class `extends RpcTarget`, so the module fails to evaluate
16
+ * with *"Class extends value undefined"* when the base is missing. That is a
17
+ * module-load error, not a test failure, so it surfaces as an unimportable
18
+ * `dav-store` barrel and no unit test can reach `DavRepository`. Deliberately
19
+ * empty: on the platform it marks which methods are callable across an RPC
20
+ * boundary, and nothing in a Node suite calls those through RPC. An empty base
21
+ * keeps the fake honest instead of pretending to implement dispatch.
22
+ * - **`WorkflowEntrypoint`** — Edge-Git, Edge-Sonic, Mail-Meow, Mail-Otter. A
23
+ * Workflow class extends it, so the mock must provide it or the module fails the
24
+ * same way — a **startup** error, which therefore takes down every suite that
25
+ * reaches `apps/background` for an unrelated reason. Edge-Sonic's is the shape
26
+ * kept: it stores `ctx` as well as `env`, because the failure policy under test
27
+ * in `runWorkflow` lives in a plain function precisely so it can be exercised
28
+ * without workerd, and that policy reads the execution context.
29
+ *
30
+ * ### Why the ambient types are declared here rather than imported
31
+ *
32
+ * The source repos name `DurableObjectState`, `ExecutionContext` and `Env`
33
+ * unqualified, which resolves only because `worker-configuration.d.ts` and
34
+ * `@cloudflare/workers-types` are ambient inside a Wrangler project. This copy is
35
+ * imported by the kit's own typecheck, where neither exists, so the two state
36
+ * shapes are declared locally and `TEnv` defaults to `unknown` instead of `Env`
37
+ * (Edge-Sonic's form). A local declaration shadows the ambient one inside this
38
+ * file only, so a consumer's copy typechecks against their generated types
39
+ * exactly as the original did.
40
+ *
41
+ * ### Usage in a consumer
42
+ *
43
+ * Copy this file to `<repo>/test/mocks/cloudflare-workers.ts` and alias the
44
+ * specifier in the Vitest config — `defineUnitVitestConfig()` already does:
45
+ *
46
+ * ```jsonc
47
+ * // wrangler.jsonc / vitest alias
48
+ * "cloudflare:workers": "test/mocks/cloudflare-workers.ts"
49
+ * ```
50
+ *
51
+ * Only what a test actually imports is exported. A symbol here that nothing
52
+ * imports is not a safety net; it is a claim that something depends on it.
53
+ */
54
+ /**
55
+ * The subset of `DurableObjectState` a Node test reaches.
56
+ *
57
+ * Declared structurally rather than imported: `id`, `storage` and `waitUntil` are
58
+ * the three a hand-driven lifecycle touches, and nothing here needs the rest.
59
+ */
60
+ export interface DurableObjectState {
61
+ readonly id: {
62
+ toString(): string;
63
+ readonly name?: string;
64
+ };
65
+ }
66
+ /**
67
+ * The subset of `ExecutionContext` a Node test reaches.
68
+ *
69
+ * `waitUntil` is present because a Workflow's `run()` is driven through it, and
70
+ * `passThroughOnException` is absent on purpose — nothing in a Node suite wires a
71
+ * request through it.
72
+ */
73
+ export interface ExecutionContext {
74
+ waitUntil(promise: Promise<unknown>): void;
75
+ }
76
+ /**
77
+ * The base class every Durable Object extends.
78
+ *
79
+ * `protected`, exactly as on the platform: a DO subclass reads `this.env` and
80
+ * `this.ctx`, and nothing outside it may.
81
+ */
82
+ declare class DurableObject<TEnv = unknown> {
83
+ protected ctx: DurableObjectState;
84
+ protected env: TEnv;
85
+ constructor(ctx: DurableObjectState, env: TEnv);
86
+ }
87
+ /**
88
+ * The base class `dofs`' `Fs` extends. See the header: an empty body is the
89
+ * whole point, and a missing class is a module-load failure.
90
+ */
91
+ declare class RpcTarget {
92
+ }
93
+ /**
94
+ * The base class every Workflow extends.
95
+ *
96
+ * `ctx` is `ExecutionContext` rather than `unknown` (Mail-Meow/Mail-Otter's
97
+ * form) because a Workflow's step code reads it; `void ctx` to silence the unused
98
+ * warning would be a lie about which of the two a subclass uses.
99
+ */
100
+ declare class WorkflowEntrypoint<TEnv = unknown> {
101
+ protected ctx: ExecutionContext;
102
+ protected env: TEnv;
103
+ constructor(ctx: ExecutionContext, env: TEnv);
104
+ }
105
+ export { DurableObject, RpcTarget, WorkflowEntrypoint };
106
+ //# sourceMappingURL=cloudflare-workers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-workers.d.ts","sourceRoot":"","sources":["../../../src/test/mocks/cloudflare-workers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE;QAAE,QAAQ,IAAI,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;GAKG;AACH,cAAM,aAAa,CAAC,IAAI,GAAG,OAAO;IAChC,SAAS,CAAC,GAAG,EAAE,kBAAkB,CAAC;IAClC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC;gBAER,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,IAAI;CAI/C;AAED;;;GAGG;AACH,cAAM,SAAS;CAAG;AAElB;;;;;;GAMG;AACH,cAAM,kBAAkB,CAAC,IAAI,GAAG,OAAO;IACrC,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC;IAChC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC;gBAER,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,IAAI;CAI7C;AAED,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Stand-in for the `cloudflare:workers` module, which has no Node equivalent.
3
+ *
4
+ * Provenance: converged from the eight copies at `test/mocks/cloudflare-workers.ts`
5
+ * (AWS-AccessBridge, CalDAV-Bridge, ChordDHT-Tracker, Durable-DAV, Edge-Git,
6
+ * Edge-Sonic, Mail-Meow, Mail-Otter). All eight are the same twenty lines; the
7
+ * union is three base classes and the union exists because each repo discovered a
8
+ * missing one the hard way.
9
+ *
10
+ * ### What each source contributes
11
+ *
12
+ * - **DurableObject** — every copy. Stores `ctx` and `env` so a real DO class can
13
+ * be constructed and its lifecycle RPCs driven directly, without Miniflare.
14
+ * - **`RpcTarget`** — Durable-DAV's, and the reason is load-bearing rather than
15
+ * tidy: `dofs`' `Fs` class `extends RpcTarget`, so the module fails to evaluate
16
+ * with *"Class extends value undefined"* when the base is missing. That is a
17
+ * module-load error, not a test failure, so it surfaces as an unimportable
18
+ * `dav-store` barrel and no unit test can reach `DavRepository`. Deliberately
19
+ * empty: on the platform it marks which methods are callable across an RPC
20
+ * boundary, and nothing in a Node suite calls those through RPC. An empty base
21
+ * keeps the fake honest instead of pretending to implement dispatch.
22
+ * - **`WorkflowEntrypoint`** — Edge-Git, Edge-Sonic, Mail-Meow, Mail-Otter. A
23
+ * Workflow class extends it, so the mock must provide it or the module fails the
24
+ * same way — a **startup** error, which therefore takes down every suite that
25
+ * reaches `apps/background` for an unrelated reason. Edge-Sonic's is the shape
26
+ * kept: it stores `ctx` as well as `env`, because the failure policy under test
27
+ * in `runWorkflow` lives in a plain function precisely so it can be exercised
28
+ * without workerd, and that policy reads the execution context.
29
+ *
30
+ * ### Why the ambient types are declared here rather than imported
31
+ *
32
+ * The source repos name `DurableObjectState`, `ExecutionContext` and `Env`
33
+ * unqualified, which resolves only because `worker-configuration.d.ts` and
34
+ * `@cloudflare/workers-types` are ambient inside a Wrangler project. This copy is
35
+ * imported by the kit's own typecheck, where neither exists, so the two state
36
+ * shapes are declared locally and `TEnv` defaults to `unknown` instead of `Env`
37
+ * (Edge-Sonic's form). A local declaration shadows the ambient one inside this
38
+ * file only, so a consumer's copy typechecks against their generated types
39
+ * exactly as the original did.
40
+ *
41
+ * ### Usage in a consumer
42
+ *
43
+ * Copy this file to `<repo>/test/mocks/cloudflare-workers.ts` and alias the
44
+ * specifier in the Vitest config — `defineUnitVitestConfig()` already does:
45
+ *
46
+ * ```jsonc
47
+ * // wrangler.jsonc / vitest alias
48
+ * "cloudflare:workers": "test/mocks/cloudflare-workers.ts"
49
+ * ```
50
+ *
51
+ * Only what a test actually imports is exported. A symbol here that nothing
52
+ * imports is not a safety net; it is a claim that something depends on it.
53
+ */
54
+ /**
55
+ * The base class every Durable Object extends.
56
+ *
57
+ * `protected`, exactly as on the platform: a DO subclass reads `this.env` and
58
+ * `this.ctx`, and nothing outside it may.
59
+ */
60
+ class DurableObject {
61
+ ctx;
62
+ env;
63
+ constructor(ctx, env) {
64
+ this.ctx = ctx;
65
+ this.env = env;
66
+ }
67
+ }
68
+ /**
69
+ * The base class `dofs`' `Fs` extends. See the header: an empty body is the
70
+ * whole point, and a missing class is a module-load failure.
71
+ */
72
+ class RpcTarget {
73
+ }
74
+ /**
75
+ * The base class every Workflow extends.
76
+ *
77
+ * `ctx` is `ExecutionContext` rather than `unknown` (Mail-Meow/Mail-Otter's
78
+ * form) because a Workflow's step code reads it; `void ctx` to silence the unused
79
+ * warning would be a lie about which of the two a subclass uses.
80
+ */
81
+ class WorkflowEntrypoint {
82
+ ctx;
83
+ env;
84
+ constructor(ctx, env) {
85
+ this.ctx = ctx;
86
+ this.env = env;
87
+ }
88
+ }
89
+ export { DurableObject, RpcTarget, WorkflowEntrypoint };
90
+ //# sourceMappingURL=cloudflare-workers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-workers.js","sourceRoot":"","sources":["../../../src/test/mocks/cloudflare-workers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAuBH;;;;;GAKG;AACH,MAAM,aAAa;IACP,GAAG,CAAqB;IACxB,GAAG,CAAO;IAEpB,YAAY,GAAuB,EAAE,GAAS;QAC5C,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,SAAS;CAAG;AAElB;;;;;;GAMG;AACH,MAAM,kBAAkB;IACZ,GAAG,CAAmB;IACtB,GAAG,CAAO;IAEpB,YAAY,GAAqB,EAAE,GAAS;QAC1C,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAED,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC"}