@lunora/codegen 1.0.0-alpha.4 → 1.0.0-alpha.40
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/LICENSE.md +6 -0
- package/__assets__/package-og.svg +1 -1
- package/dist/index.d.mts +1175 -25
- package/dist/index.d.ts +1175 -25
- package/dist/index.mjs +30 -24
- package/dist/packem_shared/{CONTAINERS_FILENAME-0K-pjNb8.mjs → CONTAINERS_FILENAME-DjpXMqhp.mjs} +1 -1
- package/dist/packem_shared/{CodegenDiagnosticError-54jWDxA9.mjs → CodegenDiagnosticError-DyQ5FwkM.mjs} +7 -5
- package/dist/packem_shared/FLAGS_FILENAME-fEZtzWXi.mjs +139 -0
- package/dist/packem_shared/GENERATED_HEADER-cUyu5VOU.mjs +3 -0
- package/dist/packem_shared/{LUNORA_ERROR_CODES-CySpQPD3.mjs → LUNORA_ERROR_CODES-DvTLozCu.mjs} +8 -1
- package/dist/packem_shared/MUTATORS_FILENAME-BZOfUhlY.mjs +81 -0
- package/dist/packem_shared/{OPENRPC_VERSION-C7zKVeKi.mjs → OPENRPC_VERSION-DxbqafcJ.mjs} +2 -2
- package/dist/packem_shared/QUEUES_FILENAME-Xv6Vy-Ku.mjs +145 -0
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-C1yHg38Z.mjs +3438 -0
- package/dist/packem_shared/{SCHEMA_SNAPSHOT_VERSION-DzLDbWk3.mjs → SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs} +18 -2
- package/dist/packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs +94 -0
- package/dist/packem_shared/{WORKFLOWS_FILENAME-DRDQdhfq.mjs → WORKFLOWS_FILENAME-B2By8S4s.mjs} +70 -2
- package/dist/packem_shared/{buildOpenApiDocument-Cns1EkCQ.mjs → buildOpenApiDocument-_mwWOc2N.mjs} +2 -2
- package/dist/packem_shared/{discoverAuthApiCalls-C35R6z0T.mjs → discoverAuthApiCalls-WMx8L2FG.mjs} +1 -1
- package/dist/packem_shared/{discoverCrons-BL6iGuJ3.mjs → discoverCrons-D-jrpm97.mjs} +22 -20
- package/dist/packem_shared/{discoverFunctions-DEgAcRuD.mjs → discoverFunctions-CZ91aenA.mjs} +72 -14
- package/dist/packem_shared/{discoverHttpRoutes-C978pBiG.mjs → discoverHttpRoutes-DNZLDCmm.mjs} +2 -2
- package/dist/packem_shared/{discoverInserts-CRQdXvHO.mjs → discoverInserts-DFRJhmCv.mjs} +24 -2
- package/dist/packem_shared/{discoverMaskProcedures-B64zA740.mjs → discoverMaskProcedures-B5iFnZ-X.mjs} +58 -2
- package/dist/packem_shared/{discoverMigrations-Doj_-BAA.mjs → discoverMigrations-CdKtMlBc.mjs} +10 -4
- package/dist/packem_shared/{discoverNondeterministicCalls-4KiPQxQU.mjs → discoverNondeterministicCalls-C_PrQPkA.mjs} +1 -1
- package/dist/packem_shared/{discoverQueries-BkIi0dBD.mjs → discoverQueries-B8W9UPrt.mjs} +1 -1
- package/dist/packem_shared/{discoverR2sqlCalls-BpDqvcUn.mjs → discoverR2sqlCalls-Bm7Rfnf4.mjs} +1 -1
- package/dist/packem_shared/{discoverRlsMetadata-DpRB1HMe.mjs → discoverRlsMetadata-B4GL4ZKm.mjs} +1 -1
- package/dist/packem_shared/{discoverSchema-BBulgGbH.mjs → discoverSchema-DFWVgU5o.mjs} +349 -17
- package/dist/packem_shared/{discoverStorageRulesMetadata-DAqJUxUv.mjs → discoverStorageRulesMetadata-nosjYcvN.mjs} +1 -1
- package/dist/packem_shared/{GENERATED_HEADER-DF1hQcix.mjs → emit-CFz-9dcD.mjs} +1100 -122
- package/dist/packem_shared/{emitApp-Ci_hcJNO.mjs → emitApp-D8rVuM__.mjs} +99 -30
- package/dist/packem_shared/formatAdvisories-DRhEiJUz.mjs +114 -0
- package/dist/packem_shared/{parse-validator-tuQtHrsr.mjs → parse-validator-BSJo1HGP.mjs} +18 -6
- package/dist/packem_shared/redact-oTmsol5A.mjs +33 -0
- package/package.json +9 -7
- package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-C5UlpWKF.mjs +0 -922
- package/dist/packem_shared/formatAdvisories-8NIv1k0I.mjs +0 -69
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Finding } from '@lunora/advisor';
|
|
2
2
|
export type { Finding } from '@lunora/advisor';
|
|
3
|
+
import { LunoraError } from '@lunora/errors';
|
|
4
|
+
export { MESSAGE_SOLUTIONS as LUNORA_SOLUTION_RULES, type Solution as LunoraSolution, type SolutionRule as LunoraSolutionRule, findSolutionByMessage as findLunoraSolution } from '@lunora/errors';
|
|
3
5
|
import { Node, Project } from 'ts-morph';
|
|
4
6
|
import { StudioFeaturesResult } from '@lunora/do';
|
|
5
7
|
import { Schema } from '@lunora/server';
|
|
@@ -25,6 +27,15 @@ interface ValidatorIR {
|
|
|
25
27
|
bucket?: string;
|
|
26
28
|
/** Column modifiers (`.unique()`, `.default()`, `.nullable()`, …) when present. */
|
|
27
29
|
column?: ColumnMetaIR;
|
|
30
|
+
/**
|
|
31
|
+
* `true` when this validator carries a `.check(...)` refinement. The predicate
|
|
32
|
+
* is a runtime closure the AST→IR step can't represent, so the node keeps its
|
|
33
|
+
* base `kind` but records the refinement's presence here. The AOT args-validator
|
|
34
|
+
* compiler declines any node with this flag (compiling it would silently skip
|
|
35
|
+
* the predicate). `.meta(...)` is pure metadata with no parse effect and does
|
|
36
|
+
* NOT set this.
|
|
37
|
+
*/
|
|
38
|
+
hasRefinement?: boolean;
|
|
28
39
|
/** For `v.optional(inner)` / `v.array(inner)`. */
|
|
29
40
|
inner?: ValidatorIR;
|
|
30
41
|
/** For `v.record(key, value)`. */
|
|
@@ -100,6 +111,36 @@ interface RelationIR {
|
|
|
100
111
|
/** Target table name. */
|
|
101
112
|
table: string;
|
|
102
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Statically-discovered `.source(...)` config (plan 077). Only the bits the
|
|
116
|
+
* advisor lints + DO wiring need are captured; `map`/`tenantBy` are functions and
|
|
117
|
+
* cannot be serialized, so their presence is recorded as `hasTenantBy` rather than
|
|
118
|
+
* the function itself.
|
|
119
|
+
*/
|
|
120
|
+
interface ExternalSourceIR {
|
|
121
|
+
/** The wrangler Hyperdrive binding name. */
|
|
122
|
+
binding: string;
|
|
123
|
+
/** Whether a `columns` projection allow-list was given. */
|
|
124
|
+
columns?: ReadonlyArray<string>;
|
|
125
|
+
/** `true` when a `reconcileEveryMs` was given (the incremental-mode delete-visibility companion). */
|
|
126
|
+
hasReconcile?: boolean;
|
|
127
|
+
/** `true` when a `tenantBy` mapper was given — the tenant-isolation boundary the `external_source_unscoped` lint checks. */
|
|
128
|
+
hasTenantBy: boolean;
|
|
129
|
+
/** The `idColumn` literal, when given (defaults to `"id"` at runtime). */
|
|
130
|
+
idColumn?: string;
|
|
131
|
+
/** Delete-detection mode literal, when given (`"full-pull"` | `"incremental"`). */
|
|
132
|
+
mode?: string;
|
|
133
|
+
/** The membership query literal, when statically knowable. */
|
|
134
|
+
query?: string;
|
|
135
|
+
/**
|
|
136
|
+
* `true` when `.source(...)` was present but its argument was **not** a static
|
|
137
|
+
* object literal (e.g. `.source(buildConfig())`), so none of the fields above
|
|
138
|
+
* could be read. The source still exists — this flag lets `hasSourcedTables`
|
|
139
|
+
* (codegen) and the `external_source_*` lints treat it as a source that can't be
|
|
140
|
+
* verified, instead of mistaking it for no `.source()` at all.
|
|
141
|
+
*/
|
|
142
|
+
unanalyzable?: boolean;
|
|
143
|
+
}
|
|
103
144
|
interface TableIR {
|
|
104
145
|
/**
|
|
105
146
|
* `true` when the table chain carried `.externallyManaged()` — its rows are
|
|
@@ -109,12 +150,26 @@ interface TableIR {
|
|
|
109
150
|
*/
|
|
110
151
|
externallyManaged?: boolean;
|
|
111
152
|
/**
|
|
153
|
+
* Set when the chain carried `.source(...)` — the table is materialized from an
|
|
154
|
+
* external Hyperdrive-backed database by a system poll loop (plan 077). Carries
|
|
155
|
+
* the statically-knowable bits the advisor lints read; the functions (`map`,
|
|
156
|
+
* `tenantBy`) are not serialized, only their presence (`hasTenantBy`).
|
|
157
|
+
*/
|
|
158
|
+
externalSource?: ExternalSourceIR;
|
|
159
|
+
/**
|
|
112
160
|
* Storage backend for a `.global()` table: `"d1"` (default) or
|
|
113
161
|
* `"hyperdrive"` (a Postgres/MySQL database via Cloudflare Hyperdrive). Only
|
|
114
162
|
* meaningful when `shardMode === "global"`; absent for sharded/root tables.
|
|
115
163
|
*/
|
|
116
164
|
globalBackend?: "d1" | "hyperdrive";
|
|
117
165
|
indexes: ReadonlyArray<IndexIR>;
|
|
166
|
+
/**
|
|
167
|
+
* `true` when the table chain carried `.public()` — an explicit opt-OUT of
|
|
168
|
+
* the schema's `.rls("required")` enforcement for this one table. Optional:
|
|
169
|
+
* hand-built IR and tables that never called `.public()` default it to
|
|
170
|
+
* `false`.
|
|
171
|
+
*/
|
|
172
|
+
isPublic?: boolean;
|
|
118
173
|
name: string;
|
|
119
174
|
/** Rank indexes declared inline via `.rankIndex(name, …)`. */
|
|
120
175
|
rankIndexes: ReadonlyArray<RankIndexIR>;
|
|
@@ -126,10 +181,30 @@ interface TableIR {
|
|
|
126
181
|
field: string;
|
|
127
182
|
kind: "shardBy";
|
|
128
183
|
};
|
|
184
|
+
/** Set when the chain carried `.softDelete()` — the marker column's name (default `deletedAt`). The column is injected into `shape` so `Doc_*` carries it. */
|
|
185
|
+
softDelete?: {
|
|
186
|
+
field: string;
|
|
187
|
+
};
|
|
129
188
|
/** Vector indexes declared inline via `.vectorize()` (DSL Shape A). */
|
|
130
189
|
vectorIndexes: ReadonlyArray<VectorIndexIR>;
|
|
131
190
|
}
|
|
191
|
+
/** The Cloudflare DO data-residency jurisdictions the schema may declare. Canonical literal set for the codegen package. */
|
|
192
|
+
type JurisdictionIR = "eu" | "fedramp" | "us";
|
|
132
193
|
interface SchemaIR {
|
|
194
|
+
/**
|
|
195
|
+
* Cloudflare data-residency jurisdiction declared via
|
|
196
|
+
* `defineSchema(...).jurisdiction("…")`. Emitted into the generated worker's
|
|
197
|
+
* `createWorker({ jurisdiction })` (and `ctx.scheduler` / `ctx.containers`).
|
|
198
|
+
* Absent ⇒ un-pinned.
|
|
199
|
+
*/
|
|
200
|
+
jurisdiction?: JurisdictionIR;
|
|
201
|
+
/**
|
|
202
|
+
* Set when `defineSchema(...).rls("required")` was chained onto the schema —
|
|
203
|
+
* every table's `ctx.db` write path is denied without an RLS-covering
|
|
204
|
+
* procedure unless the table itself is `.public()` (see {@link TableIR.isPublic}).
|
|
205
|
+
* Absent when the schema never called `.rls("required")`.
|
|
206
|
+
*/
|
|
207
|
+
rlsMode?: "required";
|
|
133
208
|
tables: ReadonlyArray<TableIR>;
|
|
134
209
|
/** All vector indexes (inline Shape A hoisted + standalone Shape B), flattened. */
|
|
135
210
|
vectorIndexes: ReadonlyArray<VectorIndexIR>;
|
|
@@ -179,6 +254,84 @@ interface MigrationIR {
|
|
|
179
254
|
table: string;
|
|
180
255
|
}
|
|
181
256
|
/**
|
|
257
|
+
* A `defineShape({...})` declaration discovered in `lunora/shapes.ts`
|
|
258
|
+
* (local-first sync engine, Phase 7). The emitted `LUNORA_SHAPES` registry keys
|
|
259
|
+
* on {@link ShapeIR.exportName}; the generated DO's `resolveShape` override
|
|
260
|
+
* dispatches a `shape_subscribe` to the matching registered shape. Discovery is
|
|
261
|
+
* marker-driven (the `__lunoraShape` brand) — no field metadata is lifted here
|
|
262
|
+
* because the runtime object (`columns`/`compileWhere`) carries the authority.
|
|
263
|
+
*/
|
|
264
|
+
interface ShapeIR {
|
|
265
|
+
/** Export binding name — the shape's registry key and import member. */
|
|
266
|
+
exportName: string;
|
|
267
|
+
/** Path relative to `<projectRoot>/lunora/` without extension — always `"shapes"`. */
|
|
268
|
+
filePath: string;
|
|
269
|
+
/**
|
|
270
|
+
* The `table` string literal from the `defineShape({ table })` call, lifted
|
|
271
|
+
* only for static advisor lints (the runtime object stays authoritative).
|
|
272
|
+
* `undefined` when `table` is not a plain string literal — lints skip those.
|
|
273
|
+
*/
|
|
274
|
+
table?: string;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The single `defineIdentity({...})` claim contract discovered in
|
|
278
|
+
* `lunora/identity.ts`. Discovery is **marker-driven** (the `__lunoraIdentity`
|
|
279
|
+
* brand, exactly like {@link ShapeIR}) — no claim metadata is lifted here
|
|
280
|
+
* because the emitted `_generated/server.ts` recovers the claim *type* from the
|
|
281
|
+
* declaration itself (`InferIdentity` over the contract's `typeof`), and the
|
|
282
|
+
* runtime object (`validate`/`onInvalid`) carries the authority at the boundary.
|
|
283
|
+
* Exactly one per app; absent ⇒ generated output is byte-identical to today.
|
|
284
|
+
*/
|
|
285
|
+
interface IdentityIR {
|
|
286
|
+
/** Export binding name — the namespace member `_generated/server.ts` reads via `typeof`. */
|
|
287
|
+
exportName: string;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The single `defineEnv({...})` contract discovered in `lunora/env.ts`. Like
|
|
291
|
+
* {@link IdentityIR}, only the export binding is lifted — the emitted
|
|
292
|
+
* `_generated/server.ts` recovers the validated shape from the declaration
|
|
293
|
+
* itself (`ReturnType` over the accessor's `typeof`), and the generated ShardDO
|
|
294
|
+
* applies the same accessor to the worker `env` at ctx-build time to populate
|
|
295
|
+
* `ctx.env`. Exactly one per app; absent ⇒ generated output is byte-identical.
|
|
296
|
+
*/
|
|
297
|
+
interface EnvIR {
|
|
298
|
+
/** Export binding name — the namespace member `_generated/server.ts` reads via `typeof`. */
|
|
299
|
+
exportName: string;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* A `defineMutator({...})` declaration discovered in `lunora/mutators.ts`
|
|
303
|
+
* (local-first sync engine, Phase 7). The emitted registry registers the
|
|
304
|
+
* authoritative `server` impl into the DO's `LUNORA_FUNCTIONS` table (so
|
|
305
|
+
* `handleRpc` transaction-wraps it) and records its path in
|
|
306
|
+
* `LUNORA_MUTATOR_PATHS` so the DO's `isCustomMutator` override routes the
|
|
307
|
+
* client-watermark push protocol. The client `client` impl is split into the
|
|
308
|
+
* browser bundle separately — only the path crosses to the server side.
|
|
309
|
+
*/
|
|
310
|
+
interface MutatorIR {
|
|
311
|
+
/** Export binding name — the mutator's registry key and import member. */
|
|
312
|
+
exportName: string;
|
|
313
|
+
/** Path relative to `<projectRoot>/lunora/` without extension — always `"mutators"`. */
|
|
314
|
+
filePath: string;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* A whole-row `ctx.db.replace(id, document)` write discovered inside a custom
|
|
318
|
+
* mutator's inline `server` impl (`lunora/mutators.ts`) — the input the
|
|
319
|
+
* `mutator_full_row_replace` advisor lint consumes. A `replace` overwrites the
|
|
320
|
+
* entire row, so a concurrent edit to a different column on a synced table is
|
|
321
|
+
* clobbered; `ctx.db.patch(id, { field })` merges at the column level instead.
|
|
322
|
+
* Structurally identical to `AdvisorMutatorWrite` so it passes straight through
|
|
323
|
+
* to the advisor without conversion, exactly as `InsertWriteIR` does for
|
|
324
|
+
* `AdvisorInsertWrite`.
|
|
325
|
+
*/
|
|
326
|
+
interface MutatorWriteIR {
|
|
327
|
+
/** The mutator export whose `server` impl performs the replace, e.g. `renameChannel`. */
|
|
328
|
+
exportName: string;
|
|
329
|
+
/** Openable source path the replace appears in — always `lunora/mutators.ts`. */
|
|
330
|
+
file: string;
|
|
331
|
+
/** 1-based line of the `replace(...)` call. */
|
|
332
|
+
line: number;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
182
335
|
* A single cron job lifted from a `cronJobs()` builder in `lunora/crons.ts`.
|
|
183
336
|
* Mirrors `@lunora/scheduler`'s `CronJob`: {@link CronJobIR.cron} is the compiled
|
|
184
337
|
* standard cron expression, {@link CronJobIR.functionPath} is the target
|
|
@@ -288,6 +441,79 @@ interface WorkflowIR {
|
|
|
288
441
|
* definition overrides it.
|
|
289
442
|
*/
|
|
290
443
|
name: string;
|
|
444
|
+
/**
|
|
445
|
+
* Durable step labels lifted from the handler body — the first string-literal
|
|
446
|
+
* argument of every `ctx.step.do` / `.sleep` / `.sleepUntil` / `.waitForEvent`
|
|
447
|
+
* call. Feeds the duplicate-step-name lint, which flags a name used twice
|
|
448
|
+
* (Cloudflare memoizes by name, so the second call silently returns the
|
|
449
|
+
* first's cached result). Calls with a non-literal name are omitted (not
|
|
450
|
+
* statically comparable).
|
|
451
|
+
*/
|
|
452
|
+
steps: ReadonlyArray<WorkflowStepIR>;
|
|
453
|
+
}
|
|
454
|
+
/** One durable step call lifted from a workflow handler body (the use side of {@link WorkflowIR.steps}). */
|
|
455
|
+
interface WorkflowStepIR {
|
|
456
|
+
/** 1-based line of the durable step call. */
|
|
457
|
+
line: number;
|
|
458
|
+
/** The native step method invoked: `do` / `sleep` / `sleepUntil` / `waitForEvent`. */
|
|
459
|
+
method: string;
|
|
460
|
+
/** The step's static label (the first string-literal argument). */
|
|
461
|
+
name: string;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* A queue lifted from a `defineQueue()` export in `lunora/queues.ts`. Carries
|
|
465
|
+
* what the emitters and the config layer need to wire the typed `ctx.queues`
|
|
466
|
+
* producer, the generated worker `queue()` dispatch, and the wrangler
|
|
467
|
+
* `queues.producers[]` / `queues.consumers[]` entries. Like workflows, a queue
|
|
468
|
+
* is NOT a Durable Object — wrangler gets only `queues.*` entries. Names are
|
|
469
|
+
* derived via `@lunora/queue`'s shared helpers so codegen and the config layer
|
|
470
|
+
* can never disagree.
|
|
471
|
+
*/
|
|
472
|
+
interface QueueIR {
|
|
473
|
+
/** The Cloudflare `Queue` producer binding name, e.g. `QUEUE_EMAIL`. */
|
|
474
|
+
bindingName: string;
|
|
475
|
+
/** The `lunora/queues.ts` export name, e.g. `emailQueue`. */
|
|
476
|
+
exportName: string;
|
|
477
|
+
/** How the queue is consumed: `"push"` (a worker `queue()` handler) or `"pull"` (external HTTP). */
|
|
478
|
+
mode: "pull" | "push";
|
|
479
|
+
/**
|
|
480
|
+
* The stable wrangler queue name (`queues.producers[].queue`). Defaults to
|
|
481
|
+
* the kebab-cased export name (`emailQueue` → `email-queue`); a static
|
|
482
|
+
* `name:` literal in the definition overrides it.
|
|
483
|
+
*/
|
|
484
|
+
name: string;
|
|
485
|
+
/** Push-consumer batch/retry tuning, mirrored onto the wrangler `queues.consumers[]` entry. */
|
|
486
|
+
tuning: {
|
|
487
|
+
deadLetterQueue?: string;
|
|
488
|
+
maxBatchSize?: number;
|
|
489
|
+
maxBatchTimeout?: number;
|
|
490
|
+
maxRetries?: number;
|
|
491
|
+
retryDelay?: number;
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* The feature-flag provider declared by the default export of `lunora/flags.ts`
|
|
496
|
+
* (`defineFlags({ provider, … })`). Discovery is **metadata-only** — codegen
|
|
497
|
+
* imports the real module at runtime for the provider value; this IR exists so
|
|
498
|
+
* the config layer can reconcile/validate the wrangler `flagship` binding when
|
|
499
|
+
* the app uses Flagship in binding mode. A `custom` provider (any other
|
|
500
|
+
* OpenFeature factory) carries no binding to reconcile.
|
|
501
|
+
*/
|
|
502
|
+
interface FlagsIR {
|
|
503
|
+
/**
|
|
504
|
+
* The wrangler `flagship[].binding` name — set **only** for a flagship
|
|
505
|
+
* `provider` in binding mode (`flagshipProvider({ binding: "FLAGS" })`). The
|
|
506
|
+
* config layer hints/validates a matching `flagship` binding from this.
|
|
507
|
+
*/
|
|
508
|
+
bindingName?: string;
|
|
509
|
+
/**
|
|
510
|
+
* Flagship operating mode — `"binding"` (wrangler binding, needs a
|
|
511
|
+
* `flagship` entry) or `"http"` (no binding); `undefined` for a `custom`
|
|
512
|
+
* provider or when the mode can't be read statically.
|
|
513
|
+
*/
|
|
514
|
+
mode?: "binding" | "http";
|
|
515
|
+
/** `"flagship"` when the provider is `flagshipProvider(...)`, else `"custom"` (any other OpenFeature provider factory). */
|
|
516
|
+
provider: "custom" | "flagship";
|
|
291
517
|
}
|
|
292
518
|
/**
|
|
293
519
|
* A `ctx.workflows.get("name")…` call discovered in a function body — the
|
|
@@ -488,6 +714,30 @@ interface MaskMetadataIR {
|
|
|
488
714
|
columns: MaskColumnMetadataIR[];
|
|
489
715
|
}
|
|
490
716
|
/**
|
|
717
|
+
* One masked column whose `mask(policies)` strategy is a statically-known
|
|
718
|
+
* literal (`"hash"` or `"redact"`) — the `mask_weak_hash_strategy_on_pii` lint
|
|
719
|
+
* input. Unlike {@link MaskColumnMetadataIR} (app-wide, deduped by `(table,
|
|
720
|
+
* column)`, studio-preview evidence), this is per declaration site (file + line
|
|
721
|
+
* + enclosing export), undeduped, so the lint can point at the exact
|
|
722
|
+
* `mask(...)` call that applies a weak strategy. A `MaskFn` (custom, non-literal)
|
|
723
|
+
* strategy carries no lint-relevant signal and is never recorded here.
|
|
724
|
+
* Structurally identical to `AdvisorMaskStrategy`.
|
|
725
|
+
*/
|
|
726
|
+
interface MaskStrategyIR {
|
|
727
|
+
/** Masked column name. */
|
|
728
|
+
column: string;
|
|
729
|
+
/** Export binding name of the procedure whose `.use(mask(...))` chain declared this column, or `"<module>"` when declared at file scope. */
|
|
730
|
+
exportName: string;
|
|
731
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
732
|
+
file: string;
|
|
733
|
+
/** 1-based line of the masked column's strategy property. */
|
|
734
|
+
line: number;
|
|
735
|
+
/** The statically-known strategy literal: `"hash"` or `"redact"`. */
|
|
736
|
+
strategy: string;
|
|
737
|
+
/** Logical table the masked column belongs to. */
|
|
738
|
+
table: string;
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
491
741
|
* One statically-readable policy entry from an `rls([...])` array literal,
|
|
492
742
|
* surfaced to the studio's read-only RLS inspector via the generated
|
|
493
743
|
* `rlsPolicies()` hook. Captures the policy's `table` + `on` operation and the
|
|
@@ -596,12 +846,18 @@ interface ProcedureMiddlewareIR {
|
|
|
596
846
|
callsMail: boolean;
|
|
597
847
|
/** Export binding name of the procedure (e.g. `signUp`). */
|
|
598
848
|
exportName: string;
|
|
849
|
+
/** `true` when the handler fans work out to a privileged, cost-bearing dispatch surface (scheduler `runAfter`/`runAt`, a queue producer send, or a workflow create). Feeds the privileged-fanout lint. */
|
|
850
|
+
fanOut: boolean;
|
|
599
851
|
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
600
852
|
file: string;
|
|
601
853
|
/** Registration kind — only `mutation`/`action` are write-shaped; `query` is read-only. */
|
|
602
854
|
kind: "action" | "mutation" | "query";
|
|
855
|
+
/** `true` when the handler runs an AI generation (`generateText`/`streamText`/`generateObject`/`streamObject`) with no `maxOutputTokens` bound in its config literal. Feeds the `ai_unbounded_generation_public` lint. */
|
|
856
|
+
unboundedAiGeneration: boolean;
|
|
603
857
|
/** `true` when the chain carries `.use(verifyTurnstile(...))` or a `protectPublic({ captcha })` bundle. */
|
|
604
858
|
usesCaptcha: boolean;
|
|
859
|
+
/** `true` when the handler calls `ctx.db.insertManyUnsafe(...)`, bypassing validators and triggers. Feeds the `insert_many_unsafe_user_data` lint. */
|
|
860
|
+
usesInsertManyUnsafe: boolean;
|
|
605
861
|
/** `true` when the chain carries `.use(mask(...))`. */
|
|
606
862
|
usesMask: boolean;
|
|
607
863
|
/** `true` when the chain carries `.use(rateLimit(...))` or a `protectPublic({ rateLimit })` bundle. */
|
|
@@ -634,6 +890,27 @@ interface ArgumentValidatorIR {
|
|
|
634
890
|
unboundedStringArgs: string[];
|
|
635
891
|
}
|
|
636
892
|
/**
|
|
893
|
+
* One factory/constructor call in `lunora/` whose config object literal a
|
|
894
|
+
* security lint inspects for a present-or-absent key — the shared input for the
|
|
895
|
+
* config-call security lints (payment authorize, inbound-mail verify, rate-limit
|
|
896
|
+
* store, browser private-targets). Structurally identical to `AdvisorConfigCall`
|
|
897
|
+
* so it passes straight through to the advisor without conversion.
|
|
898
|
+
*/
|
|
899
|
+
interface ConfigCallIR {
|
|
900
|
+
/** `true` when the config argument was a static object literal the feeder could read. */
|
|
901
|
+
analyzable: boolean;
|
|
902
|
+
/** The factory function or constructor name at the call site, e.g. `createPayment` / `RateLimiter`. */
|
|
903
|
+
callee: string;
|
|
904
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
905
|
+
file: string;
|
|
906
|
+
/** 1-based line of the call site, or `0` when unknown. */
|
|
907
|
+
line: number;
|
|
908
|
+
/** Keys present in the config object literal (empty when not `analyzable`). */
|
|
909
|
+
presentKeys: string[];
|
|
910
|
+
/** Keys in the config object literal explicitly assigned the literal `true`. */
|
|
911
|
+
trueKeys: string[];
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
637
914
|
* One secret-shaped string literal discovered in `lunora/` source — the
|
|
638
915
|
* `hardcoded_secret` lint input. Complements the pre-commit `vis secrets` scan by
|
|
639
916
|
* surfacing the same class of finding in-IDE via the studio Advisors table.
|
|
@@ -667,6 +944,308 @@ interface SqlInterpolationIR {
|
|
|
667
944
|
line: number;
|
|
668
945
|
}
|
|
669
946
|
/**
|
|
947
|
+
* One `ctx.fetch(url, …)` call inside an action whose URL argument is derived
|
|
948
|
+
* from the handler's `args` — the `action_fetch_ssrf` lint input. `ctx.fetch` is
|
|
949
|
+
* the action-only outbound-request escape hatch with no host allowlist, so a URL
|
|
950
|
+
* assembled from request input is a server-side request forgery vector (cloud
|
|
951
|
+
* metadata endpoints, internal services). Only arg-derived URLs reach here; a
|
|
952
|
+
* fixed literal or a URL built from config/`ctx.*` is not recorded. Structurally
|
|
953
|
+
* identical to `AdvisorArgumentDerivedFetch`.
|
|
954
|
+
*/
|
|
955
|
+
interface ArgumentDerivedFetchIR {
|
|
956
|
+
/** Export binding name of the action performing the `ctx.fetch` call. */
|
|
957
|
+
exportName: string;
|
|
958
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
959
|
+
file: string;
|
|
960
|
+
/** 1-based line of the `ctx.fetch` call, or `0` when unknown. */
|
|
961
|
+
line: number;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* One `ctx.kv.<method>(key, …)` call whose namespace key is derived from the
|
|
965
|
+
* handler's `args` with no server-side scoping — the `kv_unscoped_user_key_idor`
|
|
966
|
+
* lint input. Workers KV is a single flat namespace, so a key taken straight from
|
|
967
|
+
* request input lets any caller read, overwrite, or delete another user's entry
|
|
968
|
+
* (IDOR). Only arg-derived, unscoped keys reach here; a fixed literal, or a key
|
|
969
|
+
* prefixed with a server-trusted identity (`${ctx.auth.userId}:…` — references
|
|
970
|
+
* `ctx`, so treated as scoped), is not recorded. `list` is excluded (it takes a
|
|
971
|
+
* prefix, not a per-entry key). Structurally identical to `AdvisorKvKeyAccess`.
|
|
972
|
+
*/
|
|
973
|
+
interface KvKeyAccessIR {
|
|
974
|
+
/** Export binding name of the procedure performing the `ctx.kv` access. */
|
|
975
|
+
exportName: string;
|
|
976
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
977
|
+
file: string;
|
|
978
|
+
/** 1-based line of the `ctx.kv` call, or `0` when unknown. */
|
|
979
|
+
line: number;
|
|
980
|
+
/** The `ctx.kv` method invoked: `get` / `getRaw` / `getWithMetadata` / `put` / `delete`. */
|
|
981
|
+
method: string;
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* One `ctx.db` write (`insert` / `replace` / `patch` / `insertManyUnsafe`) that sets
|
|
985
|
+
* an ownership / identity column — `userId`, `ownerId`, `tenantId`, and the like —
|
|
986
|
+
* from the handler's `args` instead of the server-trusted identity. The
|
|
987
|
+
* `owner_field_from_args_not_auth` lint input: the ownership column decides who a
|
|
988
|
+
* row belongs to, so a value taken from request input lets any caller write rows
|
|
989
|
+
* owned by another user or tenant (the act-as-any-user / cross-tenant IDOR vector).
|
|
990
|
+
* A column stamped from `ctx.*`, or set to a fixed literal, is not recorded; only an
|
|
991
|
+
* arg-derived identity write reaches here. Structurally identical to
|
|
992
|
+
* `AdvisorOwnerFieldWrite`.
|
|
993
|
+
*/
|
|
994
|
+
interface OwnerFieldWriteIR {
|
|
995
|
+
/** Export binding name of the procedure performing the write. */
|
|
996
|
+
exportName: string;
|
|
997
|
+
/** The identity column being written from `args` (e.g. `userId`). */
|
|
998
|
+
field: string;
|
|
999
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1000
|
+
file: string;
|
|
1001
|
+
/** 1-based line of the `ctx.db` write call, or `0` when unknown. */
|
|
1002
|
+
line: number;
|
|
1003
|
+
/** The `ctx.db` write method (`insert` / `replace` / `patch` / `insertManyUnsafe`). */
|
|
1004
|
+
method: string;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* One `ctx.storage.<bucket>.<method>(key, …)` call whose R2 object key is derived
|
|
1008
|
+
* from the handler's `args` with no server-side scoping — the
|
|
1009
|
+
* `storage_key_from_user_args` lint input. The bucket read/write/URL/delete methods
|
|
1010
|
+
* key by their first argument, so an object key taken straight from request input is
|
|
1011
|
+
* object-level IDOR (read/overwrite/delete anyone's object). A key referencing a
|
|
1012
|
+
* server-trusted `ctx.*` value (e.g. `${ctx.auth.userId}/…`) is treated as scoped
|
|
1013
|
+
* and is not recorded; only an arg-derived, `ctx`-free key reaches here.
|
|
1014
|
+
* Structurally identical to `AdvisorStorageKeyAccess`.
|
|
1015
|
+
*/
|
|
1016
|
+
interface StorageKeyAccessIR {
|
|
1017
|
+
/** Export binding name of the procedure performing the storage call. */
|
|
1018
|
+
exportName: string;
|
|
1019
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1020
|
+
file: string;
|
|
1021
|
+
/** 1-based line of the storage call, or `0` when unknown. */
|
|
1022
|
+
line: number;
|
|
1023
|
+
/** The bucket method invoked with the arg-derived key, e.g. `get` / `put` / `delete` / `download`. */
|
|
1024
|
+
method: string;
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* One `ctx.containers.<exportName>.get(name, …)` call whose instance key is derived
|
|
1028
|
+
* from the handler's `args` with no server-side scoping — the
|
|
1029
|
+
* `container_instance_key_from_user_input` lint input. Each container definition's
|
|
1030
|
+
* `.get(name)` accessor routes to one instance per `name`, so a key taken straight from
|
|
1031
|
+
* request input lets any caller reach another tenant's container (a cross-tenant IDOR). A
|
|
1032
|
+
* fixed literal key, or one derived from a server-trusted identity (`${ctx.auth.userId}` —
|
|
1033
|
+
* references `ctx`, so treated as scoped), is not recorded; only an arg-derived, unscoped
|
|
1034
|
+
* key reaches here. `.any()`/`.pool()` take no key and are not sinks. Structurally
|
|
1035
|
+
* identical to `AdvisorContainerKeyAccess`.
|
|
1036
|
+
*/
|
|
1037
|
+
interface ContainerKeyAccessIR {
|
|
1038
|
+
/** Export binding name of the procedure performing the `ctx.containers` access. */
|
|
1039
|
+
exportName: string;
|
|
1040
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1041
|
+
file: string;
|
|
1042
|
+
/** 1-based line of the `ctx.containers.*.get` call, or `0` when unknown. */
|
|
1043
|
+
line: number;
|
|
1044
|
+
/** The container accessor method invoked — always `get`. */
|
|
1045
|
+
method: string;
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* One `ctx.ai.run(model, …)` call whose model-id argument is derived from the handler's
|
|
1049
|
+
* `args` with no server-side scoping — the `ai_raw_run_escape_hatch` lint input.
|
|
1050
|
+
* `ctx.ai.run` is the raw Workers AI binding passthrough, bypassing the typed
|
|
1051
|
+
* `ctx.ai.model(...)` + AI-SDK layer (`generateText`/`streamText`/…) that caps output and
|
|
1052
|
+
* enforces a schema, so an arg-derived model id lets any caller select an arbitrary model.
|
|
1053
|
+
* A fixed literal model, or one scoped by a server-trusted `ctx.*` value, is not recorded;
|
|
1054
|
+
* only an arg-derived, unscoped model id reaches here (an arg-derived `inputs` argument is
|
|
1055
|
+
* normal usage and is never inspected). Structurally identical to `AdvisorAiRawRun`.
|
|
1056
|
+
*/
|
|
1057
|
+
interface AiRawRunIR {
|
|
1058
|
+
/** Export binding name of the procedure performing the `ctx.ai.run` call. */
|
|
1059
|
+
exportName: string;
|
|
1060
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1061
|
+
file: string;
|
|
1062
|
+
/** 1-based line of the `ctx.ai.run` call, or `0` when unknown. */
|
|
1063
|
+
line: number;
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* One `ctx.vectors.<method>(indexName, input)` call whose `input.namespace` is derived
|
|
1067
|
+
* from the handler's `args` with no server-side scoping — the
|
|
1068
|
+
* `vectors_namespace_from_user_input` lint input. A Vectorize namespace partitions one
|
|
1069
|
+
* index into isolated sub-collections, so a namespace taken straight from request input
|
|
1070
|
+
* lets any caller read or poison another tenant's vectors. A fixed literal namespace, or
|
|
1071
|
+
* one prefixed with a server-trusted identity (`${ctx.auth.orgId}` — references `ctx`, so
|
|
1072
|
+
* treated as scoped), is not recorded; only an arg-derived, unscoped namespace reaches
|
|
1073
|
+
* here. Structurally identical to `AdvisorVectorNamespaceAccess`.
|
|
1074
|
+
*/
|
|
1075
|
+
interface VectorNamespaceAccessIR {
|
|
1076
|
+
/** Export binding name of the procedure performing the `ctx.vectors` access. */
|
|
1077
|
+
exportName: string;
|
|
1078
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1079
|
+
file: string;
|
|
1080
|
+
/** 1-based line of the `ctx.vectors` call, or `0` when unknown. */
|
|
1081
|
+
line: number;
|
|
1082
|
+
/** The `ctx.vectors` method invoked: `query` / `upsert` / `upsertMany`. */
|
|
1083
|
+
method: string;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* One `ctx.mail`/`ctx.email` `send`/`queue` call whose recipient field (`to`/`cc`/`bcc`)
|
|
1087
|
+
* is derived from the handler's `args` with no server-side scoping — the
|
|
1088
|
+
* `mail_recipient_from_request_input` lint input. A recipient taken straight from request
|
|
1089
|
+
* input turns the deployment into an open relay / spam amplifier (any caller can direct
|
|
1090
|
+
* mail to an arbitrary address). A fixed literal recipient, or one scoped by a
|
|
1091
|
+
* server-trusted `ctx.*` value (e.g. `ctx.auth.user.email`), is not recorded; only an
|
|
1092
|
+
* arg-derived, unscoped recipient reaches here. Structurally identical to
|
|
1093
|
+
* `AdvisorMailRecipientAccess`.
|
|
1094
|
+
*/
|
|
1095
|
+
interface MailRecipientAccessIR {
|
|
1096
|
+
/** Export binding name of the procedure performing the `ctx.mail`/`ctx.email` call. */
|
|
1097
|
+
exportName: string;
|
|
1098
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1099
|
+
file: string;
|
|
1100
|
+
/** 1-based line of the `ctx.mail`/`ctx.email` call, or `0` when unknown. */
|
|
1101
|
+
line: number;
|
|
1102
|
+
/** The mailer method invoked: `send` / `queue`. */
|
|
1103
|
+
method: string;
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* One `ctx.browser.<method>(url, …)` call whose navigation URL (`arguments[0]`)
|
|
1107
|
+
* is derived from the handler's `args` with no server-side scoping — the
|
|
1108
|
+
* `browser_user_url_without_allowlist` lint input. The lint additionally
|
|
1109
|
+
* cross-references `createBrowser` config-call evidence to suppress findings
|
|
1110
|
+
* when the browser is hardened with an `allowedHosts` allowlist or
|
|
1111
|
+
* `resolveDns`. Structurally identical to `AdvisorBrowserUrlAccess`.
|
|
1112
|
+
*/
|
|
1113
|
+
interface BrowserUrlAccessIR {
|
|
1114
|
+
/** Export binding name of the procedure performing the `ctx.browser` call. */
|
|
1115
|
+
exportName: string;
|
|
1116
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1117
|
+
file: string;
|
|
1118
|
+
/** 1-based line of the `ctx.browser` call, or `0` when unknown. */
|
|
1119
|
+
line: number;
|
|
1120
|
+
/** The browser method invoked: `content` / `pdf` / `scrape` / `screenshot`. */
|
|
1121
|
+
method: string;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* One runtime container-override call: a `<handle>.start({ enableInternet: true, … })`
|
|
1125
|
+
* launch override, or a `<handle>.egress.<method>(...)` runtime firewall mutation
|
|
1126
|
+
* (`allow` / `deny` / `setAllowed`) — the `container_start_enable_internet_override`
|
|
1127
|
+
* and `container_runtime_egress_relaxation` lint input. Both shapes re-open network
|
|
1128
|
+
* access the static `defineContainer` declaration (and its `container_public_internet`
|
|
1129
|
+
* lint) assumes is locked down. Matched structurally by call shape, independent of the
|
|
1130
|
+
* receiver's resolved type. Structurally identical to `AdvisorContainerOverride`.
|
|
1131
|
+
*/
|
|
1132
|
+
interface ContainerOverrideIR {
|
|
1133
|
+
/** e.g. the egress method name, or `"enableInternet: true"`. */
|
|
1134
|
+
detail: string;
|
|
1135
|
+
/** Export binding name of the procedure performing the call. */
|
|
1136
|
+
exportName: string;
|
|
1137
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1138
|
+
file: string;
|
|
1139
|
+
/** Which override shape matched. */
|
|
1140
|
+
kind: "egress_relaxation" | "enable_internet";
|
|
1141
|
+
/** 1-based line of the call, or `0` when unknown. */
|
|
1142
|
+
line: number;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* One `buildImageDeliveryUrl({ key, … })` call (`@lunora/bindings/images`) whose
|
|
1146
|
+
* `key` — the CDN transform's source image, an absolute URL or an
|
|
1147
|
+
* origin-relative key — is derived from the handler's `args` with no
|
|
1148
|
+
* server-side scoping — the `images_url_source_from_user_input` lint input.
|
|
1149
|
+
* `ctx.images.transform`/`info` take image *bytes*, never a URL, so they are not
|
|
1150
|
+
* sinks; only the `key` of `buildImageDeliveryUrl` accepts a URL-or-key source
|
|
1151
|
+
* and is inspected. An arg-derived `key` lets any caller point the CDN's
|
|
1152
|
+
* `/cdn-cgi/image/` transform at an attacker-chosen origin (SSRF / open proxy)
|
|
1153
|
+
* or at an arbitrary key under the account's own store. A fixed literal, or a
|
|
1154
|
+
* key scoped by a server-trusted `ctx.*` value, is not recorded. Structurally
|
|
1155
|
+
* identical to `AdvisorImageDeliveryUrlAccess`.
|
|
1156
|
+
*/
|
|
1157
|
+
interface ImageDeliveryUrlAccessIR {
|
|
1158
|
+
/** Export binding name of the procedure performing the `buildImageDeliveryUrl` call. */
|
|
1159
|
+
exportName: string;
|
|
1160
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1161
|
+
file: string;
|
|
1162
|
+
/** 1-based line of the `buildImageDeliveryUrl` call, or `0` when unknown. */
|
|
1163
|
+
line: number;
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* One `createAuth({...})` call's configuration snapshot — the shared input for
|
|
1167
|
+
* the five `auth_*` security lints (trusted-origins wildcard, CSRF check
|
|
1168
|
+
* disabled, secure cookies disabled, email verification disabled, session
|
|
1169
|
+
* freshAge zero). Matched by callee NAME (an `import`-agnostic, fail-closed
|
|
1170
|
+
* convention the other feeders share), so a re-export or alias still resolves.
|
|
1171
|
+
* When the config argument isn't a statically-analyzable object literal (a
|
|
1172
|
+
* top-level spread, or not an object literal at all), `analyzable` is `false`
|
|
1173
|
+
* and every boolean fact defaults to its SAFE (not-flagged) value — an opaque
|
|
1174
|
+
* config can't be relied on either way. Structurally identical to
|
|
1175
|
+
* `AdvisorAuthConfig`.
|
|
1176
|
+
*/
|
|
1177
|
+
interface AuthConfigIR {
|
|
1178
|
+
/** `true` when the call's config argument was a static object literal the feeder could read. */
|
|
1179
|
+
analyzable: boolean;
|
|
1180
|
+
/** `advanced.disableCSRFCheck === true`. */
|
|
1181
|
+
disableCsrfCheck: boolean;
|
|
1182
|
+
/** `emailAndPassword.enabled === true`. */
|
|
1183
|
+
emailPasswordEnabled: boolean;
|
|
1184
|
+
/** Export binding name enclosing the `createAuth(...)` call. */
|
|
1185
|
+
exportName: string;
|
|
1186
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1187
|
+
file: string;
|
|
1188
|
+
/** 1-based line of the `createAuth(...)` call, or `0` when unknown. */
|
|
1189
|
+
line: number;
|
|
1190
|
+
/** `emailAndPassword.requireEmailVerification === true` present. */
|
|
1191
|
+
requireEmailVerification: boolean;
|
|
1192
|
+
/** `advanced.useSecureCookies === false`. */
|
|
1193
|
+
secureCookiesDisabled: boolean;
|
|
1194
|
+
/** `session.freshAge === 0` (explicit literal). */
|
|
1195
|
+
sessionFreshAgeZero: boolean;
|
|
1196
|
+
/** `trustedOrigins` array literal contains a `"*"` element. */
|
|
1197
|
+
trustedOriginsWildcard: boolean;
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* One `rateLimit`/`dbRateLimit` middleware call (`@lunora/ratelimit`) whose
|
|
1201
|
+
* `key` selector — the per-caller rate-limit sub-key, `(ctx) => string |
|
|
1202
|
+
* undefined` — is derived from the handler's `args` with no server-side
|
|
1203
|
+
* scoping (no reference to the trusted `ctx` binding anywhere in the selector)
|
|
1204
|
+
* — the `ratelimit_key_spoofable_or_global` lint input. A key an attacker
|
|
1205
|
+
* controls lets them rotate it per request and bypass the limit entirely,
|
|
1206
|
+
* defeating its purpose. A selector scoped by `ctx` (e.g. `ctx.auth.userId`,
|
|
1207
|
+
* `ctx.ip`), or one with no `args` reference at all (a fixed/global bucket —
|
|
1208
|
+
* the "no key" case this lint deliberately does not flag, to keep it low-FP),
|
|
1209
|
+
* is not recorded. Structurally identical to `AdvisorRatelimitKeySelector`.
|
|
1210
|
+
*/
|
|
1211
|
+
interface RatelimitKeySelectorIR {
|
|
1212
|
+
/** The `rateLimit`/`dbRateLimit` callee invoked. */
|
|
1213
|
+
callee: string;
|
|
1214
|
+
/** Export binding name of the procedure whose `.use(...)` chain carries the call. */
|
|
1215
|
+
exportName: string;
|
|
1216
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1217
|
+
file: string;
|
|
1218
|
+
/** The rate limit's `name` argument (the second positional argument), or `""` when not a string literal. */
|
|
1219
|
+
limitName: string;
|
|
1220
|
+
/** 1-based line of the `rateLimit`/`dbRateLimit` call, or `0` when unknown. */
|
|
1221
|
+
line: number;
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* One payload-derived privileged dispatch — a `ctx.run`/`context.run` back into a
|
|
1225
|
+
* Lunora function from inside a `defineQueue` push handler or a `defineWorkflow`
|
|
1226
|
+
* handler, whose args reference the handler's untrusted payload (`context.params`
|
|
1227
|
+
* for a workflow, a `for (… of batch.messages)` body for a queue) — the
|
|
1228
|
+
* `privileged_dispatch_unvalidated_payload` lint input. Both handler kinds run
|
|
1229
|
+
* under the **system identity** (RLS disabled), so forwarding attacker-influenced
|
|
1230
|
+
* payload into the dispatch bypasses the target's row policy. The resolved
|
|
1231
|
+
* `targetFile`/`targetExport` let the lint join RLS-procedure evidence and fire
|
|
1232
|
+
* only for RLS-gated targets. Structurally identical to `AdvisorPrivilegedDispatch`.
|
|
1233
|
+
*/
|
|
1234
|
+
interface PrivilegedDispatchIR {
|
|
1235
|
+
/** `"queue"` for a `defineQueue` handler, `"workflow"` for a `defineWorkflow` handler. */
|
|
1236
|
+
dispatchKind: "queue" | "workflow";
|
|
1237
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1238
|
+
file: string;
|
|
1239
|
+
/** Export binding name of the handler performing the dispatch. */
|
|
1240
|
+
handlerExport: string;
|
|
1241
|
+
/** 1-based line of the dispatch call, or `0` when unknown. */
|
|
1242
|
+
line: number;
|
|
1243
|
+
/** Export name of the dispatched target (`send` in `api.messages.send`). */
|
|
1244
|
+
targetExport: string;
|
|
1245
|
+
/** File path of the dispatched target relative to `lunora/` (`messages` in `api.messages.send`). */
|
|
1246
|
+
targetFile: string;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
670
1249
|
* One discovered `httpRoute.<verb>("/admin/…")` route on an admin/privileged-looking
|
|
671
1250
|
* path, with whether its builder chain references an auth/admin guard — the
|
|
672
1251
|
* `admin_route_without_guard` lint input. Structurally identical to
|
|
@@ -684,6 +1263,317 @@ interface AdminRouteIR {
|
|
|
684
1263
|
/** `true` when the handler body references an auth/session/admin guard (`ctx.auth`, `getSession`, `requireAdmin`, …). */
|
|
685
1264
|
usesGuard: boolean;
|
|
686
1265
|
}
|
|
1266
|
+
/**
|
|
1267
|
+
* One tracked `ctx.storage.<bucket>.<method>(...)` upload/signing call — the
|
|
1268
|
+
* shared input for the storage config-hygiene security lints
|
|
1269
|
+
* (`storage_upload_without_content_type_allowlist`, `storage_upload_without_max_size`,
|
|
1270
|
+
* `storage_generate_upload_url_no_content_type_pin`, `storage_presigned_url_for_private_content`).
|
|
1271
|
+
* `upload`/`store` carry the `UploadOptions` guards (`allowedContentTypes` /
|
|
1272
|
+
* `maxSize`); `generateUploadUrl` carries the signed-PUT `contentType` pin;
|
|
1273
|
+
* `getPresignedUrl`/`getSignedUrl` carry a statically-known `expiresInSeconds`
|
|
1274
|
+
* literal. `presentKeys` is empty (and `expiresInSeconds` unset) when the
|
|
1275
|
+
* options argument was absent, a non-literal, or a spread — see `analyzable`.
|
|
1276
|
+
* Structurally identical to `AdvisorStorageUpload`.
|
|
1277
|
+
*/
|
|
1278
|
+
interface StorageUploadIR {
|
|
1279
|
+
/** `true` when the call's options-object argument (or its deliberate absence) was statically resolvable. */
|
|
1280
|
+
analyzable: boolean;
|
|
1281
|
+
/** Numeric literal value of an `expiresInSeconds` option, when statically known (`getSignedUrl` / `getPresignedUrl` only). */
|
|
1282
|
+
expiresInSeconds?: number;
|
|
1283
|
+
/** Export binding name of the procedure performing the call. */
|
|
1284
|
+
exportName: string;
|
|
1285
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1286
|
+
file: string;
|
|
1287
|
+
/** 1-based line of the call, or `0` when unknown. */
|
|
1288
|
+
line: number;
|
|
1289
|
+
/** The `ctx.storage` method invoked. */
|
|
1290
|
+
method: "generateUploadUrl" | "getPresignedUrl" | "getSignedUrl" | "store" | "upload";
|
|
1291
|
+
/** Options-object keys present at the call site (empty when not `analyzable`, or when no options argument was passed). */
|
|
1292
|
+
presentKeys: string[];
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* One discovered `httpAction`/`httpRoute` handler in `lunora/` that performs a
|
|
1296
|
+
* side effect (`ctx.runMutation` / `ctx.runAction` / a `ctx.db.{insert,patch,
|
|
1297
|
+
* replace,delete,insertManyUnsafe}` write) from the HTTP edge, with whether it
|
|
1298
|
+
* reads `ctx.auth` — the `http_action_missing_auth_guard` lint input. A handler
|
|
1299
|
+
* that mutates state or dispatches an action without ever consulting the request
|
|
1300
|
+
* identity is an unauthenticated write bypassing identity/RLS. Only handlers with
|
|
1301
|
+
* a statically-resolvable inline body and `ctx` binding are recorded (fail-safe
|
|
1302
|
+
* under-report); read-only handlers are never recorded. Structurally identical to
|
|
1303
|
+
* `AdvisorHttpActionGuard`.
|
|
1304
|
+
*/
|
|
1305
|
+
interface HttpActionGuardIR {
|
|
1306
|
+
/** Export binding name of the handler (or `"<module>"` when mounted inline / not a named binding). */
|
|
1307
|
+
exportName: string;
|
|
1308
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1309
|
+
file: string;
|
|
1310
|
+
/** Which HTTP surface the handler is: a raw `httpAction` or a typed `httpRoute` route. */
|
|
1311
|
+
kind: "httpAction" | "httpRoute";
|
|
1312
|
+
/** 1-based line of the handler call, or `0` when unknown. */
|
|
1313
|
+
line: number;
|
|
1314
|
+
/** For an `httpRoute`, the uppercased verb (`"POST"`); absent for a raw `httpAction`. */
|
|
1315
|
+
method?: string;
|
|
1316
|
+
/** `true` when the handler reads `ctx.auth` (a direct member access or a `const { auth } = ctx` destructure). */
|
|
1317
|
+
readsAuth: boolean;
|
|
1318
|
+
/** The first side effect found, as a stable label: `runMutation`, `runAction`, or `db.<method>`. */
|
|
1319
|
+
sideEffect: string;
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* One response-header write, inside an `httpAction` handler, whose value is derived
|
|
1323
|
+
* from raw request input (`request.headers`, `request.url`/query, `await
|
|
1324
|
+
* request.json()`) with no CR/LF sanitizer — the
|
|
1325
|
+
* `http_action_response_header_injection` lint input. A `Request`-derived string
|
|
1326
|
+
* placed verbatim into a response header lets a caller smuggle `\r\n` and inject
|
|
1327
|
+
* extra headers or split the response (header injection / response splitting). Only
|
|
1328
|
+
* sites whose value is request-tainted AND unguarded are recorded: a value routed
|
|
1329
|
+
* through a CR/LF guard (`isSafeHeaderValue`), a URL/URI encoder
|
|
1330
|
+
* (`encodeURIComponent`/`encodeURI`), a numeric coercion (`Number`/`parseInt`/
|
|
1331
|
+
* `parseFloat`), or `btoa` is treated as safe and never recorded (`String(...)` /
|
|
1332
|
+
* `.toString()` are NOT sanitizers — they don't strip CR/LF). Structurally
|
|
1333
|
+
* identical to `AdvisorHttpHeaderWrite`.
|
|
1334
|
+
*/
|
|
1335
|
+
interface HttpHeaderWriteIR {
|
|
1336
|
+
/** Export binding name of the enclosing handler, or `"<module>"` when mounted inline. */
|
|
1337
|
+
exportName: string;
|
|
1338
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1339
|
+
file: string;
|
|
1340
|
+
/** The header name being written (`"location"`), or `""` when the key is not a string literal. */
|
|
1341
|
+
headerName: string;
|
|
1342
|
+
/** 1-based line of the request-tainted header value. */
|
|
1343
|
+
line: number;
|
|
1344
|
+
/** How the header was written. */
|
|
1345
|
+
via: "headers-append" | "headers-ctor" | "headers-set" | "response-init";
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* One rate-limit / Turnstile middleware call in `lunora/` — the
|
|
1349
|
+
* `ratelimit_middleware_fail_open` lint input. `rateLimit`/`dbRateLimit`
|
|
1350
|
+
* (`@lunora/ratelimit`) and `verifyTurnstileMiddleware` (`@lunora/auth`) each
|
|
1351
|
+
* accept a `failOpen` escape hatch that admits every request when the
|
|
1352
|
+
* limiter/siteverify is unavailable; `failOpen` is `true` only when the options
|
|
1353
|
+
* literal set it to the boolean literal `true` (anything else is fail-closed).
|
|
1354
|
+
* The lint escalates a fail-open guard to a finding when the guarded procedure
|
|
1355
|
+
* (`exportName`/`limitName`) looks auth/payment-sensitive. Structurally
|
|
1356
|
+
* identical to `AdvisorFailOpenGuard`.
|
|
1357
|
+
*/
|
|
1358
|
+
interface FailOpenGuardIR {
|
|
1359
|
+
/** The middleware factory at the call site: `rateLimit` / `dbRateLimit` / `verifyTurnstileMiddleware`. */
|
|
1360
|
+
callee: string;
|
|
1361
|
+
/** Export binding name of the procedure the guard is attached to, or `"<module>"` at file scope. */
|
|
1362
|
+
exportName: string;
|
|
1363
|
+
/** `true` only when the options literal set `failOpen: true` as a boolean literal; a non-literal or absent option is treated as fail-closed. */
|
|
1364
|
+
failOpen: boolean;
|
|
1365
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1366
|
+
file: string;
|
|
1367
|
+
/** The rate-limit `name` (second string argument) for `rateLimit`/`dbRateLimit`; `""` for `verifyTurnstileMiddleware`. */
|
|
1368
|
+
limitName: string;
|
|
1369
|
+
/** 1-based line of the middleware call, or `0` when unknown. */
|
|
1370
|
+
line: number;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* One `ctx.flags.boolean("key", <boolean-literal>)` read in `lunora/` — the
|
|
1374
|
+
* `flag_gates_security_with_unsafe_default` lint input. OpenFeature returns the
|
|
1375
|
+
* `defaultValue` when the provider errors, so a fail-open default on a
|
|
1376
|
+
* security-shaped key silently opens access during an outage. Only reads with a
|
|
1377
|
+
* statically-known string key and boolean-literal default are recorded; the lint
|
|
1378
|
+
* owns the security-shape + polarity judgment. Structurally identical to
|
|
1379
|
+
* `AdvisorFlagSecurityDefault`.
|
|
1380
|
+
*/
|
|
1381
|
+
interface FlagSecurityDefaultIR {
|
|
1382
|
+
/** The boolean-literal default returned on a provider outage (fail-open value). */
|
|
1383
|
+
defaultValue: boolean;
|
|
1384
|
+
/** Export binding name of the procedure performing the flag read, or `"<module>"` at file scope. */
|
|
1385
|
+
exportName: string;
|
|
1386
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1387
|
+
file: string;
|
|
1388
|
+
/** The flag key — the first string-literal argument of `ctx.flags.boolean`. */
|
|
1389
|
+
key: string;
|
|
1390
|
+
/** 1-based line of the `ctx.flags.boolean` call, or `0` when unknown. */
|
|
1391
|
+
line: number;
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* One `generateText` / `streamText` call in `lunora/` whose `tools` reach a
|
|
1395
|
+
* privileged side effect (a DB write, function dispatch, or outbound
|
|
1396
|
+
* fetch/mail/queue send). `userInputDerived` records whether the model input
|
|
1397
|
+
* (`prompt`/`messages`/`system`) flows from the handler's `args`; the
|
|
1398
|
+
* `ai_tool_side_effect_prompt_injection` lint fires only when it does.
|
|
1399
|
+
* Structurally identical to `AdvisorAiToolSideEffect`.
|
|
1400
|
+
*/
|
|
1401
|
+
interface AiToolSideEffectIR {
|
|
1402
|
+
/** Export binding name of the procedure performing the call. */
|
|
1403
|
+
exportName: string;
|
|
1404
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1405
|
+
file: string;
|
|
1406
|
+
/** 1-based line of the generation call, or `0` when unknown. */
|
|
1407
|
+
line: number;
|
|
1408
|
+
/** The generation entrypoint invoked. */
|
|
1409
|
+
method: "generateText" | "streamText";
|
|
1410
|
+
/** The privileged side-effect sink a model-callable tool reaches (`ctx.db.insert`, `ctx.run`, `ctx.fetch`, …). */
|
|
1411
|
+
sideEffect: string;
|
|
1412
|
+
/** `true` when a model-input option is derived from the handler's `args` (a bare `args.x`, or a name destructured from `args`). */
|
|
1413
|
+
userInputDerived: boolean;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* One `<receiver>.identity.<key>` claim read in `lunora/`, where `<receiver>` is
|
|
1417
|
+
* an RLS/mask policy `auth` (or `ctx.auth`/`context.auth`). `declared` records
|
|
1418
|
+
* whether `<key>` is in the app's `defineIdentity({ ... })` contract (or the
|
|
1419
|
+
* always-present `userId`); the `identity_undeclared_claim_trusted` lint fires on
|
|
1420
|
+
* the undeclared reads. Emitted only when a resolvable identity contract exists.
|
|
1421
|
+
* Structurally identical to `AdvisorIdentityClaimRead`.
|
|
1422
|
+
*/
|
|
1423
|
+
interface IdentityClaimReadIR {
|
|
1424
|
+
/** `true` when `key` is a declared claim (in the `defineIdentity` contract, or the always-present `userId`). */
|
|
1425
|
+
declared: boolean;
|
|
1426
|
+
/** Export binding name of the enclosing declaration (`<module>` at file scope). */
|
|
1427
|
+
exportName: string;
|
|
1428
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1429
|
+
file: string;
|
|
1430
|
+
/** The claim key read off the identity bag. */
|
|
1431
|
+
key: string;
|
|
1432
|
+
/** 1-based line of the read, or `0` when unknown. */
|
|
1433
|
+
line: number;
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* One payment webhook-adapter construction in `lunora/` (`createStripeAdapter` /
|
|
1437
|
+
* `createPolarAdapter` / `createAutumnAdapter` / `createDodoPaymentsAdapter`).
|
|
1438
|
+
* `toleranceSeconds` carries the statically-known `webhookToleranceSeconds`
|
|
1439
|
+
* replay window when it is a plain numeric literal; the payment-webhook
|
|
1440
|
+
* wide-tolerance lint fires when it exceeds a conservative ceiling. Structurally
|
|
1441
|
+
* identical to `AdvisorPaymentWebhook`.
|
|
1442
|
+
*/
|
|
1443
|
+
interface PaymentWebhookIR {
|
|
1444
|
+
/** The adapter factory invoked. */
|
|
1445
|
+
callee: "createAutumnAdapter" | "createDodoPaymentsAdapter" | "createPolarAdapter" | "createStripeAdapter";
|
|
1446
|
+
/** Export binding name of the enclosing declaration (`<module>` at file scope). */
|
|
1447
|
+
exportName: string;
|
|
1448
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1449
|
+
file: string;
|
|
1450
|
+
/** 1-based line of the construction, or `0` when unknown. */
|
|
1451
|
+
line: number;
|
|
1452
|
+
/** Statically-known `webhookToleranceSeconds` literal, when present and a plain numeric literal. */
|
|
1453
|
+
toleranceSeconds?: number;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* One `ctx.db.<table>.findMany({ includeDeleted })` list read whose
|
|
1457
|
+
* `includeDeleted` is either a hardcoded `true` or derived from the handler's
|
|
1458
|
+
* `args` — the `soft_delete_include_deleted_from_args` lint input. The lint joins
|
|
1459
|
+
* `table` against the schema's soft-delete tables and `visibility` against
|
|
1460
|
+
* `.public()` before flagging. Structurally identical to `AdvisorSoftDeleteRead`
|
|
1461
|
+
* so values pass straight through without conversion.
|
|
1462
|
+
*/
|
|
1463
|
+
interface SoftDeleteReadIR {
|
|
1464
|
+
/** Export binding name of the procedure performing the read. */
|
|
1465
|
+
exportName: string;
|
|
1466
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1467
|
+
file: string;
|
|
1468
|
+
/** `true` when `includeDeleted` was derived from the handler's `args` (any caller can flip it). */
|
|
1469
|
+
fromArgs: boolean;
|
|
1470
|
+
/** `true` when `includeDeleted` was a hardcoded `true` literal (always resurfaces soft-deleted rows). */
|
|
1471
|
+
hardcodedTrue: boolean;
|
|
1472
|
+
/** 1-based line of the read call. */
|
|
1473
|
+
line: number;
|
|
1474
|
+
/** Table read, or `""` when the table-arg form's first argument wasn't a string literal. */
|
|
1475
|
+
table: string;
|
|
1476
|
+
/** `"internal"` for `internalQuery` / `internalMutation` / `internalAction`. */
|
|
1477
|
+
visibility: "internal" | "public";
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* One `ctx.db.<table>.findMany({ with: { <rel> } })` relation-hydrating list read
|
|
1481
|
+
* — the `masked_relation_leak_via_with` lint input. Column masking does not
|
|
1482
|
+
* descend into `with`-hydrated relations, so a masked table surfaced only through
|
|
1483
|
+
* a `with` on an unprotected parent read is returned in the clear. The lint
|
|
1484
|
+
* resolves each relation accessor to its target table and joins it against the
|
|
1485
|
+
* discovered mask evidence before flagging. Structurally identical to
|
|
1486
|
+
* `AdvisorRelationLoad` so values pass straight through without conversion.
|
|
1487
|
+
*/
|
|
1488
|
+
interface RelationLoadIR {
|
|
1489
|
+
/** Export binding name of the procedure performing the read. */
|
|
1490
|
+
exportName: string;
|
|
1491
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1492
|
+
file: string;
|
|
1493
|
+
/** 1-based line of the read call. */
|
|
1494
|
+
line: number;
|
|
1495
|
+
/** Parent table the read targets, or `""` when the table-arg form's first argument wasn't a string literal. */
|
|
1496
|
+
parentTable: string;
|
|
1497
|
+
/** Relation accessor names named in the read's `with: { … }` map — matched against the parent table's declared relations. */
|
|
1498
|
+
relations: string[];
|
|
1499
|
+
/** `"internal"` for `internalQuery` / `internalMutation` / `internalAction`. */
|
|
1500
|
+
visibility: "internal" | "public";
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* One `query` handler whose `return` hands back the raw rows of a table — the
|
|
1504
|
+
* result of a `ctx.db.<table>.findMany()` / `.findFirst()` / `.get()` read, or a
|
|
1505
|
+
* `ctx.db.query("<table>")…collect()` fluent chain — returned directly (or through
|
|
1506
|
+
* one local `const` hop) with no hand-built projection. The
|
|
1507
|
+
* `output_projection_missing_on_public_read` lint keeps only `visibility ===
|
|
1508
|
+
* "public"` rows with no `.output(...)` / `.use(mask(...))` on the chain, then
|
|
1509
|
+
* joins `table` against the schema and flags one whose columns are PII-named.
|
|
1510
|
+
* Structurally identical to `AdvisorRawRowReturn` so values pass straight through
|
|
1511
|
+
* without conversion.
|
|
1512
|
+
*/
|
|
1513
|
+
interface RawRowReturnIR {
|
|
1514
|
+
/** Export binding name of the query returning the raw rows. */
|
|
1515
|
+
exportName: string;
|
|
1516
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1517
|
+
file: string;
|
|
1518
|
+
/** 1-based line of the `return` (or concise-body) expression. */
|
|
1519
|
+
line: number;
|
|
1520
|
+
/** Table whose raw rows are returned, or `""` when the read's table wasn't a string literal. */
|
|
1521
|
+
table: string;
|
|
1522
|
+
/** `true` when the procedure's builder chain carries a `.use(mask(...))` step. */
|
|
1523
|
+
usesMask: boolean;
|
|
1524
|
+
/** `true` when the procedure's builder chain carries an `.output(...)` return-shape projection. */
|
|
1525
|
+
usesOutput: boolean;
|
|
1526
|
+
/** `"internal"` for `internalQuery`; `"public"` for `query`. */
|
|
1527
|
+
visibility: "internal" | "public";
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* One `query`/`mutation` handler that gates a `ctx.db.get`/`patch`/`delete` on a
|
|
1531
|
+
* null-checked `ctx.db.normalizeId(table, id)` result — the
|
|
1532
|
+
* `normalize_id_used_as_authorization` lint input. `normalizeId` validates an id's
|
|
1533
|
+
* structural shape only (it never reads the database), so a non-null result proves
|
|
1534
|
+
* the id is well-formed, never that the caller owns the row; gating access on it is
|
|
1535
|
+
* an IDOR. The lint owns the negative proof — it keeps only `visibility === "public"`
|
|
1536
|
+
* rows with no `.use(rls(...))` and no ownership/identity mention (`mentionsOwnership`),
|
|
1537
|
+
* then joins `table` against the schema's RLS mode before flagging. Structurally
|
|
1538
|
+
* identical to `AdvisorNormalizeIdAuthorization` so values pass straight through.
|
|
1539
|
+
*/
|
|
1540
|
+
interface NormalizeIdAuthorizationIR {
|
|
1541
|
+
/** Export binding name of the procedure performing the normalize-then-access. */
|
|
1542
|
+
exportName: string;
|
|
1543
|
+
/** Source file relative to `<projectRoot>/lunora/`, without extension. */
|
|
1544
|
+
file: string;
|
|
1545
|
+
/** 1-based line of the `ctx.db.normalizeId(...)` call the access is gated on. */
|
|
1546
|
+
line: number;
|
|
1547
|
+
/** `true` when the handler anywhere reads an ownership-named identifier or `ctx.auth`/`ctx.identity`/… — an intervening ownership signal. */
|
|
1548
|
+
mentionsOwnership: boolean;
|
|
1549
|
+
/** The id-first `ctx.db` sink the normalized id reaches. */
|
|
1550
|
+
sinkMethod: "delete" | "get" | "patch";
|
|
1551
|
+
/** Table named in the `normalizeId` call, or `""` when its table argument wasn't a string literal. */
|
|
1552
|
+
table: string;
|
|
1553
|
+
/** `true` when the procedure's builder chain carries a `.use(rls(...))` step. */
|
|
1554
|
+
usesRls: boolean;
|
|
1555
|
+
/** `"internal"` for `internalQuery`/`internalMutation`; `"public"` for `query`/`mutation`. */
|
|
1556
|
+
visibility: "internal" | "public";
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* One committed `wrangler.jsonc` `vars` entry whose value is a plaintext secret —
|
|
1560
|
+
* the `plaintext_secret_in_wrangler_vars` lint input. `vars` are baked into the
|
|
1561
|
+
* deployed Worker in cleartext and checked into source control, so a real API key
|
|
1562
|
+
* / token / private key there ships the secret to every reader of the repo and the
|
|
1563
|
+
* bundle; it belongs in a Secrets Store binding or `wrangler secret put`. Produced
|
|
1564
|
+
* by `@lunora/config` (which reads `wrangler.jsonc`), not a ts-morph feeder —
|
|
1565
|
+
* codegen only passes it through. Structurally identical to `AdvisorWranglerVariable`.
|
|
1566
|
+
*/
|
|
1567
|
+
interface WranglerVariableIR {
|
|
1568
|
+
/** The `wrangler.jsonc` file the var was read from, relative to the project root. */
|
|
1569
|
+
file: string;
|
|
1570
|
+
/** The offending `vars` key (e.g. `STRIPE_SECRET_KEY`). */
|
|
1571
|
+
key: string;
|
|
1572
|
+
/** Heuristic that matched, e.g. `stripe_live_key` / `private_key` / `secret_named_var`. */
|
|
1573
|
+
kind: string;
|
|
1574
|
+
/** Redacted preview of the value (first few chars + length) for the finding detail — never the full secret. */
|
|
1575
|
+
preview: string;
|
|
1576
|
+
}
|
|
687
1577
|
interface ProjectIR {
|
|
688
1578
|
crons: ReadonlyArray<CronJobIR>;
|
|
689
1579
|
functions: ReadonlyArray<FunctionIR>;
|
|
@@ -696,17 +1586,78 @@ interface ProjectIR {
|
|
|
696
1586
|
* Run the static lints against a discovered {@link SchemaIR} and the reads/writes/calls
|
|
697
1587
|
* found in function bodies: query reads feed `filter_without_index`, insert writes
|
|
698
1588
|
* feed `table_without_insert`, authApi calls feed `auth_api_call_without_headers`,
|
|
699
|
-
* rls procedure snapshots feed `rls_uncovered_table`,
|
|
700
|
-
* snapshots feed `mask_uncovered_pii_column
|
|
701
|
-
* feed
|
|
702
|
-
*
|
|
1589
|
+
* rls procedure snapshots feed `rls_uncovered_table`, mask procedure
|
|
1590
|
+
* snapshots feed `mask_uncovered_pii_column`, and per-column mask strategies
|
|
1591
|
+
* feed `mask_weak_hash_strategy_on_pii`; declared containers
|
|
1592
|
+
* feed the `container_*` lints; declared workflows (with their durable step labels)
|
|
1593
|
+
* + `ctx.workflows.get(...)` call sites feed the `workflow_unused` /
|
|
1594
|
+
* `workflow_unknown_target` / duplicate-step-name lints; non-deterministic
|
|
703
1595
|
* calls inside query/mutation handlers feed the `nondeterministic_query_mutation` lint
|
|
704
1596
|
* (all default empty for callers that don't analyze functions/containers/workflows).
|
|
705
1597
|
* The IR types are structurally identical to the advisor's evidence types so they
|
|
706
1598
|
* pass straight through without conversion. Returns the findings; surfacing them
|
|
707
1599
|
* (console, error overlay, studio Advisors table) is the caller's choice.
|
|
708
1600
|
*/
|
|
709
|
-
|
|
1601
|
+
/**
|
|
1602
|
+
* Named inputs for {@link lintSchema}. Every feeder is a discrete key rather than
|
|
1603
|
+
* a positional argument: the feeder list grows every few releases and many IR
|
|
1604
|
+
* types are structurally similar (`{file, exportName, line}`-shaped evidence),
|
|
1605
|
+
* so a positional call was a silent-transposition hazard — swapping two adjacent
|
|
1606
|
+
* arguments could typecheck yet feed the wrong evidence to the wrong lint and
|
|
1607
|
+
* corrupt a security advisory. `schema` is the only required field; every other
|
|
1608
|
+
* feeder defaults to "not analyzed" when omitted.
|
|
1609
|
+
*/
|
|
1610
|
+
interface LintSchemaOptions {
|
|
1611
|
+
adminRoutes?: ReadonlyArray<AdminRouteIR>;
|
|
1612
|
+
aiRawRuns?: ReadonlyArray<AiRawRunIR>;
|
|
1613
|
+
aiToolSideEffects?: ReadonlyArray<AiToolSideEffectIR>;
|
|
1614
|
+
argumentDerivedFetches?: ReadonlyArray<ArgumentDerivedFetchIR>;
|
|
1615
|
+
argumentValidators?: ReadonlyArray<ArgumentValidatorIR>;
|
|
1616
|
+
authApiCalls?: ReadonlyArray<AuthApiCallIR>;
|
|
1617
|
+
authConfigs?: ReadonlyArray<AuthConfigIR>;
|
|
1618
|
+
browserUrlAccesses?: ReadonlyArray<BrowserUrlAccessIR>;
|
|
1619
|
+
configCalls?: ReadonlyArray<ConfigCallIR>;
|
|
1620
|
+
containerKeyAccesses?: ReadonlyArray<ContainerKeyAccessIR>;
|
|
1621
|
+
containerOverrides?: ReadonlyArray<ContainerOverrideIR>;
|
|
1622
|
+
containers?: ReadonlyArray<ContainerIR>;
|
|
1623
|
+
failOpenGuards?: ReadonlyArray<FailOpenGuardIR>;
|
|
1624
|
+
flagSecurityDefaults?: ReadonlyArray<FlagSecurityDefaultIR>;
|
|
1625
|
+
httpActionGuards?: ReadonlyArray<HttpActionGuardIR>;
|
|
1626
|
+
httpHeaderWrites?: ReadonlyArray<HttpHeaderWriteIR>;
|
|
1627
|
+
identityClaimReads?: ReadonlyArray<IdentityClaimReadIR>;
|
|
1628
|
+
imageDeliveryUrlAccesses?: ReadonlyArray<ImageDeliveryUrlAccessIR>;
|
|
1629
|
+
inserts?: ReadonlyArray<InsertWriteIR>;
|
|
1630
|
+
kvKeyAccesses?: ReadonlyArray<KvKeyAccessIR>;
|
|
1631
|
+
mailRecipientAccesses?: ReadonlyArray<MailRecipientAccessIR>;
|
|
1632
|
+
maskProcedures?: ReadonlyArray<MaskProcedureIR>;
|
|
1633
|
+
maskStrategies?: ReadonlyArray<MaskStrategyIR>;
|
|
1634
|
+
mutatorWrites?: ReadonlyArray<MutatorWriteIR>;
|
|
1635
|
+
nondeterministicCalls?: ReadonlyArray<NondeterministicCallIR>;
|
|
1636
|
+
normalizeIdAuthorizations?: ReadonlyArray<NormalizeIdAuthorizationIR>;
|
|
1637
|
+
ownerFieldWrites?: ReadonlyArray<OwnerFieldWriteIR>;
|
|
1638
|
+
paymentWebhooks?: ReadonlyArray<PaymentWebhookIR>;
|
|
1639
|
+
privilegedDispatches?: ReadonlyArray<PrivilegedDispatchIR>;
|
|
1640
|
+
procedureProtections?: ReadonlyArray<ProcedureMiddlewareIR>;
|
|
1641
|
+
queries?: ReadonlyArray<QueryReadIR>;
|
|
1642
|
+
queues?: ReadonlyArray<QueueIR>;
|
|
1643
|
+
r2sqlCalls?: ReadonlyArray<R2sqlCallIR>;
|
|
1644
|
+
ratelimitKeySelectors?: ReadonlyArray<RatelimitKeySelectorIR>;
|
|
1645
|
+
rawRowReturns?: ReadonlyArray<RawRowReturnIR>;
|
|
1646
|
+
relationLoads?: ReadonlyArray<RelationLoadIR>;
|
|
1647
|
+
rlsProcedures?: ReadonlyArray<RlsProcedureIR>;
|
|
1648
|
+
schema: SchemaIR;
|
|
1649
|
+
secretLiterals?: ReadonlyArray<SecretLiteralIR>;
|
|
1650
|
+
shapes?: ReadonlyArray<ShapeIR>;
|
|
1651
|
+
softDeleteReads?: ReadonlyArray<SoftDeleteReadIR>;
|
|
1652
|
+
sqlInterpolations?: ReadonlyArray<SqlInterpolationIR>;
|
|
1653
|
+
storageKeyAccesses?: ReadonlyArray<StorageKeyAccessIR>;
|
|
1654
|
+
storageUploads?: ReadonlyArray<StorageUploadIR>;
|
|
1655
|
+
vectorNamespaceAccesses?: ReadonlyArray<VectorNamespaceAccessIR>;
|
|
1656
|
+
workflowCalls?: ReadonlyArray<WorkflowCallIR>;
|
|
1657
|
+
workflows?: ReadonlyArray<WorkflowIR>;
|
|
1658
|
+
wranglerVariables?: ReadonlyArray<WranglerVariableIR>;
|
|
1659
|
+
}
|
|
1660
|
+
declare const lintSchema: (options: LintSchemaOptions) => Finding[];
|
|
710
1661
|
/**
|
|
711
1662
|
* Render advisor findings as a single multi-line string for console surfacing:
|
|
712
1663
|
* a one-line summary header followed by one `[LEVEL] name: detail` line per
|
|
@@ -716,10 +1667,12 @@ declare const formatAdvisories: (findings: ReadonlyArray<Finding>) => string;
|
|
|
716
1667
|
/**
|
|
717
1668
|
* An error thrown by codegen discovery when the user's schema or function
|
|
718
1669
|
* source has a structural problem that can be pinpointed to a specific source
|
|
719
|
-
* location.
|
|
720
|
-
*
|
|
1670
|
+
* location. A `LunoraError` subclass (`code: "CODEGEN_DIAGNOSTIC"`); the `file`,
|
|
1671
|
+
* `line`, and `column` properties (also passed through as the base `loc`) mirror
|
|
1672
|
+
* what Vite's error-overlay `loc` field expects so the browser can display the
|
|
1673
|
+
* exact spot.
|
|
721
1674
|
*/
|
|
722
|
-
declare class CodegenDiagnosticError extends
|
|
1675
|
+
declare class CodegenDiagnosticError extends LunoraError {
|
|
723
1676
|
readonly column: number;
|
|
724
1677
|
readonly file: string;
|
|
725
1678
|
readonly line: number;
|
|
@@ -731,8 +1684,14 @@ declare class CodegenDiagnosticError extends Error {
|
|
|
731
1684
|
* ts-morph `Node`'s position in its source file.
|
|
732
1685
|
*
|
|
733
1686
|
* Message format: `@lunora/codegen: <detail> (<file>:<line>:<column>)`
|
|
1687
|
+
*
|
|
1688
|
+
* `meta` is merged onto the returned error for callers that also carry the
|
|
1689
|
+
* project-wide `LunoraError` envelope (`code`/`name`/`status`) — it never
|
|
1690
|
+
* touches `file`/`line`/`column`, and the error stays an instance of
|
|
1691
|
+
* {@link CodegenDiagnosticError} so the Vite overlay's `instanceof` location
|
|
1692
|
+
* lookup is unaffected.
|
|
734
1693
|
*/
|
|
735
|
-
declare const diagnosticAt: (node: Node, detail: string) => CodegenDiagnosticError;
|
|
1694
|
+
declare const diagnosticAt: (node: Node, detail: string, meta?: Record<string, unknown>) => CodegenDiagnosticError;
|
|
736
1695
|
/**
|
|
737
1696
|
* Discover `ctx.authApi.<method>(...)` (and bare `authApi.<method>(...)`) calls
|
|
738
1697
|
* under the lunora source directory and attribute each to the exported function
|
|
@@ -758,6 +1717,21 @@ declare const discoverContainers: (project: Project, lunoraDirectory: string) =>
|
|
|
758
1717
|
* workflow start. Names must be unique across the project.
|
|
759
1718
|
*/
|
|
760
1719
|
declare const discoverCrons: (project: Project, lunoraDirectory: string, workflows?: ReadonlyArray<WorkflowIR>) => CronJobIR[];
|
|
1720
|
+
/** The only file a feature-flag provider may be declared in — mirrors `lunora/queues.ts`. */
|
|
1721
|
+
declare const FLAGS_FILENAME = "flags.ts";
|
|
1722
|
+
/** One statically-discovered flag read: the key plus the value type its `ctx.flags.<type>` call implies. */
|
|
1723
|
+
|
|
1724
|
+
/**
|
|
1725
|
+
* Discover the feature-flag provider a project declares in `lunora/flags.ts`.
|
|
1726
|
+
* Returns `undefined` when the file doesn't exist (the app has no flags). The
|
|
1727
|
+
* read is metadata-only and lenient: codegen wires `ctx.flags` purely from the
|
|
1728
|
+
* file's *existence* (`run-codegen.ts`) and imports the real module for the
|
|
1729
|
+
* provider value — this IR exists solely so the config layer can reconcile the
|
|
1730
|
+
* wrangler `flagship` binding for the Flagship binding-mode provider. Anything
|
|
1731
|
+
* it can't read statically degrades to a `custom` provider (no binding), never
|
|
1732
|
+
* a thrown error.
|
|
1733
|
+
*/
|
|
1734
|
+
declare const discoverFlags: (project: Project, lunoraDirectory: string) => FlagsIR | undefined;
|
|
761
1735
|
/**
|
|
762
1736
|
* Scan all .ts files under `lunoraDir` (skipping `_generated/` and `schema.ts`)
|
|
763
1737
|
* for top-level `export const x = query/mutation/action({...})` registrations.
|
|
@@ -800,6 +1774,23 @@ declare const discoverMaskProcedures: (project: Project, lunoraDirectory: string
|
|
|
800
1774
|
* key); `table` is best-effort and left `""` when not a literal.
|
|
801
1775
|
*/
|
|
802
1776
|
declare const discoverMigrations: (project: Project, lunoraDirectory: string) => MigrationIR[];
|
|
1777
|
+
/** The only file custom mutators may be declared in — mirrors `lunora/queues.ts`. */
|
|
1778
|
+
declare const MUTATORS_FILENAME = "mutators.ts";
|
|
1779
|
+
/**
|
|
1780
|
+
* Decide whether a call's callee is `defineMutator` — either the bare imported
|
|
1781
|
+
* identifier (`defineMutator(...)`) or a namespace member access
|
|
1782
|
+
* (`server.defineMutator(...)`). Both are valid ES module syntax, so discovery
|
|
1783
|
+
* must see mutators declared either way.
|
|
1784
|
+
*/
|
|
1785
|
+
|
|
1786
|
+
/**
|
|
1787
|
+
* Discover every custom mutator the project declares: exported
|
|
1788
|
+
* `defineMutator()` calls in `lunora/mutators.ts`. Returns `[]` when the file
|
|
1789
|
+
* doesn't exist. Only the export binding is lifted — the runtime object carries
|
|
1790
|
+
* the authoritative `server` impl + `handler`, so codegen never evaluates the
|
|
1791
|
+
* body. The client `client` impl is split into the browser bundle separately.
|
|
1792
|
+
*/
|
|
1793
|
+
declare const discoverMutators: (project: Project, lunoraDirectory: string) => MutatorIR[];
|
|
803
1794
|
/**
|
|
804
1795
|
* Discover non-deterministic API calls (`Date.now`, `new Date()`, `Date()`,
|
|
805
1796
|
* `Math.random`, `crypto.randomUUID`, `crypto.getRandomValues` — including
|
|
@@ -823,6 +1814,15 @@ declare const discoverNondeterministicCalls: (project: Project, lunoraDirectory:
|
|
|
823
1814
|
* dropping the rest keeps the lint input small.
|
|
824
1815
|
*/
|
|
825
1816
|
declare const discoverQueries: (project: Project, lunoraDirectory: string) => QueryReadIR[];
|
|
1817
|
+
/** The only file queues may be declared in — mirrors `lunora/workflows.ts`. */
|
|
1818
|
+
declare const QUEUES_FILENAME = "queues.ts";
|
|
1819
|
+
/**
|
|
1820
|
+
* Discover every queue the project declares: exported `defineQueue()` calls in
|
|
1821
|
+
* `lunora/queues.ts`. Returns `[]` when the file doesn't exist. Only the
|
|
1822
|
+
* wrangler-relevant literals (`name`/`mode`/batch tuning) are read; the handler
|
|
1823
|
+
* body is runtime-only, so codegen never evaluates it.
|
|
1824
|
+
*/
|
|
1825
|
+
declare const discoverQueues: (project: Project, lunoraDirectory: string) => QueueIR[];
|
|
826
1826
|
/**
|
|
827
1827
|
* Discover `ctx.r2sql` accesses lexically inside the handler body of every
|
|
828
1828
|
* exported `query(...)` / `mutation(...)` registration under the lunora source
|
|
@@ -855,7 +1855,17 @@ declare const discoverRlsMetadata: (project: Project, lunoraDirectory: string) =
|
|
|
855
1855
|
* Load `<projectRoot>/lunora/schema.ts`, find `defineSchema({...})`, and
|
|
856
1856
|
* return a structural IR. Throws if the file or call cannot be found.
|
|
857
1857
|
*/
|
|
858
|
-
declare const discoverSchema: (project: Project, schemaPath: string) => SchemaIR;
|
|
1858
|
+
declare const discoverSchema: (project: Project, schemaPath: string, projectRoot?: string) => SchemaIR;
|
|
1859
|
+
/** The only file shapes may be declared in — mirrors `lunora/queues.ts`. */
|
|
1860
|
+
declare const SHAPES_FILENAME = "shapes.ts";
|
|
1861
|
+
/**
|
|
1862
|
+
* Discover every replication shape the project declares: exported
|
|
1863
|
+
* `defineShape()` calls in `lunora/shapes.ts`. Returns `[]` when the file
|
|
1864
|
+
* doesn't exist. Only the export binding is lifted — the runtime object carries
|
|
1865
|
+
* the authoritative `table`/`columns`/`compileWhere`, so codegen never
|
|
1866
|
+
* evaluates the predicate.
|
|
1867
|
+
*/
|
|
1868
|
+
declare const discoverShapes: (project: Project, lunoraDirectory: string) => ShapeIR[];
|
|
859
1869
|
/**
|
|
860
1870
|
* Aggregate the schema-wide storage-rule metadata the studio's inspector reads:
|
|
861
1871
|
* every statically-discovered `(bucket, on, prefix, procedure)` entry across all
|
|
@@ -894,24 +1904,69 @@ declare const emitApi: (functions: ReadonlyArray<FunctionIR>, workflows?: Readon
|
|
|
894
1904
|
* Returns `""` when `@lunora/seed` is not a declared dependency, so projects
|
|
895
1905
|
* that don't use it keep a clean `_generated/` and never import the package.
|
|
896
1906
|
*/
|
|
1907
|
+
|
|
1908
|
+
/**
|
|
1909
|
+
* Emit `_generated/collections.ts` — one TanStack DB collection factory per
|
|
1910
|
+
* `defineShape` in `lunora/shapes.ts` (the local-first partial-replication
|
|
1911
|
+
* surface). Each factory builds a live collection that syncs its shape's rowset
|
|
1912
|
+
* through the client's poke protocol (`subscribeShape`), so an app feeds the
|
|
1913
|
+
* result straight to `useLiveQuery`.
|
|
1914
|
+
*
|
|
1915
|
+
* Returns `""` (so `writeIfPresent` skips the file) unless the project both
|
|
1916
|
+
* declares shapes AND installs `@lunora/db` — the add-on that ships
|
|
1917
|
+
* `lunoraCollectionOptions`. `@lunora/db` stays a scoped install even under the
|
|
1918
|
+
* `lunorash` umbrella (an opt-in add-on, like `@lunora/auth`), so its import is
|
|
1919
|
+
* always `@lunora/db/collections`; only the in-umbrella `@lunora/client` import
|
|
1920
|
+
* is remapped to `lunorash/client`.
|
|
1921
|
+
*/
|
|
1922
|
+
declare const emitCollections: (shapes: ReadonlyArray<ShapeIR>, hasDatabase: boolean, useUmbrella?: boolean) => string;
|
|
897
1923
|
interface EmitServerOptions {
|
|
898
1924
|
containers?: ReadonlyArray<ContainerIR>;
|
|
1925
|
+
/**
|
|
1926
|
+
* The single `defineEnv(...)` contract declared in `lunora/env.ts`. When
|
|
1927
|
+
* present, `ctx.env` is typed as the validated `InferEnv` shape (recovered
|
|
1928
|
+
* via `ReturnType` over the accessor's `typeof`). `undefined` leaves `ctx.env`
|
|
1929
|
+
* the base optional binding record — byte-identical to today.
|
|
1930
|
+
*/
|
|
1931
|
+
env?: EnvIR;
|
|
1932
|
+
/**
|
|
1933
|
+
* A `lunora/` source reads `ctx.access` — wires the verified Cloudflare Access
|
|
1934
|
+
* facade (`@lunora/cloudflare-access/context`) onto every ctx. Distinct from
|
|
1935
|
+
* `emitApp`'s `hasAccess` (which gates the worker's `.access()` resolveIdentity
|
|
1936
|
+
* method); this one gates the per-request `ctx.access` read surface.
|
|
1937
|
+
*/
|
|
1938
|
+
hasAccessFacade?: boolean;
|
|
899
1939
|
hasAi?: boolean;
|
|
900
|
-
/** A `lunora/` source uses `@lunora/analytics` / `ctx.analytics` — wires the write helper onto every ctx. */
|
|
1940
|
+
/** A `lunora/` source uses `@lunora/bindings/analytics` / `ctx.analytics` — wires the write helper onto every ctx. */
|
|
901
1941
|
hasAnalytics?: boolean;
|
|
902
1942
|
/** A `lunora/` source uses `@lunora/browser` / `ctx.browser` — wires `ctx.browser` onto ActionCtx only. */
|
|
903
1943
|
hasBrowser?: boolean;
|
|
1944
|
+
/** The project declares `lunora/flags.ts` — wires `ctx.flags` (OpenFeature) onto every ctx. */
|
|
1945
|
+
hasFlags?: boolean;
|
|
904
1946
|
/** A `lunora/` source uses `@lunora/hyperdrive` / `ctx.sql` — wires `ctx.sql` onto ActionCtx only. */
|
|
905
1947
|
hasHyperdrive?: boolean;
|
|
906
|
-
/** A `lunora/` source uses `@lunora/images` / `ctx.images` — wires `ctx.images` onto ActionCtx only. */
|
|
1948
|
+
/** A `lunora/` source uses `@lunora/bindings/images` / `ctx.images` — wires `ctx.images` onto ActionCtx only. */
|
|
907
1949
|
hasImages?: boolean;
|
|
908
|
-
/** A `lunora/` source uses `@lunora/kv` / `ctx.kv` — wires `ctx.kv` onto every ctx. */
|
|
1950
|
+
/** A `lunora/` source uses `@lunora/bindings/kv` / `ctx.kv` — wires `ctx.kv` onto every ctx. */
|
|
909
1951
|
hasKv?: boolean;
|
|
910
1952
|
hasPayments?: boolean;
|
|
911
|
-
/** A `lunora/` source uses `@lunora/pipelines` / `ctx.pipelines` — wires `ctx.pipelines` onto ActionCtx only. */
|
|
1953
|
+
/** A `lunora/` source uses `@lunora/bindings/pipelines` / `ctx.pipelines` — wires `ctx.pipelines` onto ActionCtx only. */
|
|
912
1954
|
hasPipelines?: boolean;
|
|
913
|
-
/** A `lunora/` source uses `@lunora/r2sql` / `ctx.r2sql` — wires `ctx.r2sql` onto ActionCtx only. */
|
|
1955
|
+
/** A `lunora/` source uses `@lunora/bindings/r2sql` / `ctx.r2sql` — wires `ctx.r2sql` onto ActionCtx only. */
|
|
914
1956
|
hasR2sql?: boolean;
|
|
1957
|
+
/** A `lunora/` source uses `@lunora/x402/pay` / `ctx.x402` — wires the agent-wallet pay rail onto ActionCtx only. */
|
|
1958
|
+
hasX402?: boolean;
|
|
1959
|
+
/**
|
|
1960
|
+
* The single `defineIdentity(...)` claim contract declared in
|
|
1961
|
+
* `lunora/identity.ts` (Plan 080). When present, `ctx.auth.getIdentity()`,
|
|
1962
|
+
* the RLS policy `ctx.auth.identity`, and the shard-authorization hooks
|
|
1963
|
+
* narrow to the declared shape (recovered via `InferIdentity` over the
|
|
1964
|
+
* contract's `typeof`). `undefined` keeps the identity an untyped bag —
|
|
1965
|
+
* byte-identical to today.
|
|
1966
|
+
*/
|
|
1967
|
+
identity?: IdentityIR;
|
|
1968
|
+
/** Queues declared via `defineQueue` exports — wires the typed `ctx.queues` producers onto Mutation/Action contexts. */
|
|
1969
|
+
queues?: ReadonlyArray<QueueIR>;
|
|
915
1970
|
schema?: SchemaIR;
|
|
916
1971
|
storageRuleBuckets?: ReadonlyArray<string>;
|
|
917
1972
|
/** The project depends on the `lunora` umbrella — import base packages via its subpaths. */
|
|
@@ -920,21 +1975,27 @@ interface EmitServerOptions {
|
|
|
920
1975
|
}
|
|
921
1976
|
declare const emitServer: ({
|
|
922
1977
|
containers,
|
|
1978
|
+
env,
|
|
1979
|
+
hasAccessFacade,
|
|
923
1980
|
hasAi,
|
|
924
1981
|
hasAnalytics,
|
|
925
1982
|
hasBrowser,
|
|
1983
|
+
hasFlags,
|
|
926
1984
|
hasHyperdrive,
|
|
927
1985
|
hasImages,
|
|
928
1986
|
hasKv,
|
|
929
1987
|
hasPayments,
|
|
930
1988
|
hasPipelines,
|
|
931
1989
|
hasR2sql,
|
|
1990
|
+
hasX402,
|
|
1991
|
+
identity,
|
|
1992
|
+
queues,
|
|
932
1993
|
schema,
|
|
933
1994
|
storageRuleBuckets,
|
|
934
1995
|
useUmbrella,
|
|
935
1996
|
workflows
|
|
936
1997
|
}?: EmitServerOptions) => string;
|
|
937
|
-
declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>) => string;
|
|
1998
|
+
declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?: ReadonlyArray<MigrationIR>, useUmbrella?: boolean, mutators?: ReadonlyArray<MutatorIR>, shapes?: ReadonlyArray<ShapeIR>) => string;
|
|
938
1999
|
/**
|
|
939
2000
|
* Storage-column map per table for the file browser: `{ table: [field, …] }` for
|
|
940
2001
|
* every field declared `v.storage(...)` (unwrapping `v.optional(...)`). The
|
|
@@ -952,7 +2013,7 @@ declare const emitFunctions: (functions: ReadonlyArray<FunctionIR>, migrations?:
|
|
|
952
2013
|
* `containers[].class_name` to be exported by the deployed worker. Returns ""
|
|
953
2014
|
* when the project declares no containers (the file is not written then).
|
|
954
2015
|
*/
|
|
955
|
-
declare const emitContainers: (containers: ReadonlyArray<ContainerIR
|
|
2016
|
+
declare const emitContainers: (containers: ReadonlyArray<ContainerIR>, jurisdiction?: JurisdictionIR) => string;
|
|
956
2017
|
/**
|
|
957
2018
|
* Emit `_generated/workflows.ts` — one `WorkflowEntrypoint` class per
|
|
958
2019
|
* `defineWorkflow` export, each a thin subclass of `LunoraWorkflow`
|
|
@@ -962,14 +2023,33 @@ declare const emitContainers: (containers: ReadonlyArray<ContainerIR>) => string
|
|
|
962
2023
|
* when the project declares no workflows (the file is not written then).
|
|
963
2024
|
*/
|
|
964
2025
|
declare const emitWorkflows: (workflows: ReadonlyArray<WorkflowIR>) => string;
|
|
2026
|
+
/**
|
|
2027
|
+
* Emit `_generated/queues.ts` — the push-consumer registry the worker `queue()`
|
|
2028
|
+
* handler dispatches through. Maps each push queue's stable wrangler name (which
|
|
2029
|
+
* `batch.queue` carries) to its `defineQueue` definition + export name. Pull
|
|
2030
|
+
* queues are consumed by an external worker, so they carry no handler and are
|
|
2031
|
+
* omitted here. Returns "" (and the file is not written) when no push queues are
|
|
2032
|
+
* declared — a pull-only or queue-free app keeps a clean `_generated/`.
|
|
2033
|
+
*/
|
|
965
2034
|
interface EmitShardOptions {
|
|
966
2035
|
advisories?: ReadonlyArray<Finding>;
|
|
967
2036
|
containers?: ReadonlyArray<ContainerIR>;
|
|
2037
|
+
/** The single `defineEnv(...)` contract declared in `lunora/env.ts` — applies the accessor to the worker `env` to populate `ctx.env`. */
|
|
2038
|
+
env?: EnvIR;
|
|
2039
|
+
/** Statically-discovered `ctx.flags.<type>("key")` reads — the studio Flags page + reactive evaluation iterate these. */
|
|
2040
|
+
flagKeys?: ReadonlyArray<{
|
|
2041
|
+
key: string;
|
|
2042
|
+
type: "boolean" | "number" | "object" | "string";
|
|
2043
|
+
}>;
|
|
2044
|
+
/** A `lunora/` source reads `ctx.access` — wires the verified Cloudflare Access facade onto every ctx. */
|
|
2045
|
+
hasAccessFacade?: boolean;
|
|
968
2046
|
hasAi?: boolean;
|
|
969
2047
|
/** A `lunora/` source reads `ctx.analytics` — wires the Analytics Engine write helper onto every ctx. */
|
|
970
2048
|
hasAnalytics?: boolean;
|
|
971
2049
|
/** A `lunora/` source reads `ctx.browser` — wires `ctx.browser` onto the ActionCtx only. */
|
|
972
2050
|
hasBrowser?: boolean;
|
|
2051
|
+
/** The project declares `lunora/flags.ts` — wires `ctx.flags` (OpenFeature) onto every ctx. */
|
|
2052
|
+
hasFlags?: boolean;
|
|
973
2053
|
/** A `lunora/` source reads `ctx.sql` (Hyperdrive) — wires `ctx.sql` onto the ActionCtx only. */
|
|
974
2054
|
hasHyperdrive?: boolean;
|
|
975
2055
|
/** A `lunora/` source reads `ctx.images` — wires `ctx.images` onto the ActionCtx only. */
|
|
@@ -977,11 +2057,21 @@ interface EmitShardOptions {
|
|
|
977
2057
|
/** A `lunora/` source reads `ctx.kv` — wires `ctx.kv` onto every ctx. */
|
|
978
2058
|
hasKv?: boolean;
|
|
979
2059
|
hasPayments?: boolean;
|
|
2060
|
+
/** A `lunora/` source reads `ctx.pipelines` — wires `ctx.pipelines` onto the ActionCtx only. */
|
|
2061
|
+
hasPipelines?: boolean;
|
|
980
2062
|
/** A `lunora/` source reads `ctx.r2sql` (R2 SQL) — wires `ctx.r2sql` onto the ActionCtx only. */
|
|
981
2063
|
hasR2sql?: boolean;
|
|
2064
|
+
/** A `lunora/` source reads `ctx.x402` — wires the agent-wallet pay rail onto the ActionCtx only. */
|
|
2065
|
+
hasX402?: boolean;
|
|
982
2066
|
maskMetadata?: MaskMetadataIR;
|
|
2067
|
+
/** Custom mutators declared via `defineMutator` in `lunora/mutators.ts` — wires the `isCustomMutator` push-protocol override. */
|
|
2068
|
+
mutators?: ReadonlyArray<MutatorIR>;
|
|
2069
|
+
/** Queues declared via `defineQueue` exports in `lunora/queues.ts` — wires the typed `ctx.queues` producers. */
|
|
2070
|
+
queues?: ReadonlyArray<QueueIR>;
|
|
983
2071
|
rlsMetadata?: RlsMetadataIR;
|
|
984
2072
|
schema: SchemaIR;
|
|
2073
|
+
/** Replication shapes declared via `defineShape` in `lunora/shapes.ts` — wires the `resolveShape` subscription override. */
|
|
2074
|
+
shapes?: ReadonlyArray<ShapeIR>;
|
|
985
2075
|
storageRules?: StorageRulesMetadataIR;
|
|
986
2076
|
studioFeatures?: StudioFeaturesResult;
|
|
987
2077
|
/** The project depends on the `lunora` umbrella — import base packages via its subpaths. */
|
|
@@ -991,17 +2081,26 @@ interface EmitShardOptions {
|
|
|
991
2081
|
declare const emitShard: ({
|
|
992
2082
|
advisories,
|
|
993
2083
|
containers,
|
|
2084
|
+
env,
|
|
2085
|
+
flagKeys,
|
|
2086
|
+
hasAccessFacade,
|
|
994
2087
|
hasAi,
|
|
995
2088
|
hasAnalytics,
|
|
996
2089
|
hasBrowser,
|
|
2090
|
+
hasFlags,
|
|
997
2091
|
hasHyperdrive,
|
|
998
2092
|
hasImages,
|
|
999
2093
|
hasKv,
|
|
1000
2094
|
hasPayments,
|
|
2095
|
+
hasPipelines,
|
|
1001
2096
|
hasR2sql,
|
|
2097
|
+
hasX402,
|
|
1002
2098
|
maskMetadata,
|
|
2099
|
+
mutators,
|
|
2100
|
+
queues,
|
|
1003
2101
|
rlsMetadata,
|
|
1004
2102
|
schema,
|
|
2103
|
+
shapes,
|
|
1005
2104
|
storageRules,
|
|
1006
2105
|
studioFeatures,
|
|
1007
2106
|
useUmbrella,
|
|
@@ -1066,9 +2165,11 @@ declare const emitVectors: (vectorIndexes: ReadonlyArray<VectorIndexIR>) => stri
|
|
|
1066
2165
|
declare const emitWranglerCronTriggers: (crons: ReadonlyArray<CronJobIR>) => string[];
|
|
1067
2166
|
/** Which capability methods the generated `defineApp` builder exposes — one flag per package-backed feature the app actually uses. */
|
|
1068
2167
|
interface EmitAppOptions {
|
|
2168
|
+
/** App depends on `@lunora/cloudflare-access` → emit `.access()` (wire the Cloudflare Access `resolveIdentity`, composed ahead of `@lunora/auth` when both are present). */
|
|
2169
|
+
hasAccess: boolean;
|
|
1069
2170
|
/** App uses `@lunora/ai` / `ctx.ai` → emit `.ai()` (override the Workers AI binding backing `ctx.ai`). */
|
|
1070
2171
|
hasAi: boolean;
|
|
1071
|
-
/** App uses `@lunora/analytics` / `ctx.analytics` → emit `.analytics()` (override the dataset backing `ctx.analytics`). */
|
|
2172
|
+
/** App uses `@lunora/bindings/analytics` / `ctx.analytics` → emit `.analytics()` (override the dataset backing `ctx.analytics`). */
|
|
1072
2173
|
hasAnalytics: boolean;
|
|
1073
2174
|
/** App depends on `@lunora/auth` → emit `.auth()` + the lazy build/migrate dance. */
|
|
1074
2175
|
hasAuth: boolean;
|
|
@@ -1082,13 +2183,15 @@ interface EmitAppOptions {
|
|
|
1082
2183
|
hasHyperdrive: boolean;
|
|
1083
2184
|
/** Schema declares **Hyperdrive-backed** `.global({ backend: "hyperdrive" })` tables → emit `.hyperdriveGlobal()` (reactive Postgres/MySQL ctx-db over Hyperdrive). */
|
|
1084
2185
|
hasHyperdriveGlobal: boolean;
|
|
1085
|
-
/** App uses `@lunora/images` / `ctx.images` → emit `.images()`. */
|
|
2186
|
+
/** App uses `@lunora/bindings/images` / `ctx.images` → emit `.images()`. */
|
|
1086
2187
|
hasImages: boolean;
|
|
1087
|
-
/** App uses `@lunora/kv` / `ctx.kv` → emit `.kv()`. */
|
|
2188
|
+
/** App uses `@lunora/bindings/kv` / `ctx.kv` → emit `.kv()`. */
|
|
1088
2189
|
hasKv: boolean;
|
|
1089
2190
|
/** App uses `@lunora/payment` / `ctx.payments` → emit `.payment()`. */
|
|
1090
2191
|
hasPayments: boolean;
|
|
1091
|
-
/** App
|
|
2192
|
+
/** App declares push queues (`defineQueue`) → wire `LUNORA_QUEUE_REGISTRY` into the worker's `queue()` consumer entry. */
|
|
2193
|
+
hasQueue: boolean;
|
|
2194
|
+
/** App uses `@lunora/bindings/r2sql` / `ctx.r2sql` → emit `.r2sql()`. */
|
|
1092
2195
|
hasR2sql: boolean;
|
|
1093
2196
|
/** App imports `@lunora/scheduler` / declares crons → emit `.scheduler()`. */
|
|
1094
2197
|
hasScheduler: boolean;
|
|
@@ -1098,6 +2201,12 @@ interface EmitAppOptions {
|
|
|
1098
2201
|
hasVectors: boolean;
|
|
1099
2202
|
/** App declares Cloudflare Workflows (`defineWorkflow`) → wire `options.workflowsClient` so the studio's workflow-instance proxy can reach the CF REST API. */
|
|
1100
2203
|
hasWorkflow: boolean;
|
|
2204
|
+
/** App uses `@lunora/x402/pay` / `ctx.x402` → emit `.x402()` (wire the agent-wallet pay rail). */
|
|
2205
|
+
hasX402: boolean;
|
|
2206
|
+
/** The single `defineIdentity(...)` contract in `lunora/identity.ts` (Plan 080) → import it as a VALUE and wire `options.identity`, so the runtime trust boundary validates every resolved identity before it becomes `ctx.auth`. `undefined` ⇒ no wiring, byte-identical output. */
|
|
2207
|
+
identity?: IdentityIR;
|
|
2208
|
+
/** Schema declares `.jurisdiction("…")` → pin every DO the worker reaches (shards, fan-out, scheduler, containers) to the Cloudflare data-residency jurisdiction. */
|
|
2209
|
+
jurisdiction?: JurisdictionIR;
|
|
1101
2210
|
/** Project depends on the unscoped `lunorash` umbrella → import the runtime via `lunorash/runtime` instead of `@lunora/runtime`. */
|
|
1102
2211
|
useUmbrella: boolean;
|
|
1103
2212
|
/** An OpenAPI spec is emitted (`openapi.ts`) → wire `openApiSpec` into the worker. */
|
|
@@ -1242,6 +2351,19 @@ interface TableSnapshot {
|
|
|
1242
2351
|
}
|
|
1243
2352
|
/** The committed baseline — a deterministic structural view of the whole schema. */
|
|
1244
2353
|
interface SchemaSnapshot {
|
|
2354
|
+
/**
|
|
2355
|
+
* Cloudflare DO data-residency jurisdiction declared via `.jurisdiction("…")`,
|
|
2356
|
+
* or absent. Tracked because changing it strands all existing Durable Object
|
|
2357
|
+
* data (a DO name maps to a different ID per jurisdiction). Optional, so old
|
|
2358
|
+
* baselines written before this field parse cleanly (absent ⇒ undefined).
|
|
2359
|
+
*
|
|
2360
|
+
* Typed as a plain `string` (not the authoring union) on purpose: this is
|
|
2361
|
+
* STORED data that a newer Lunora may have written with a jurisdiction this
|
|
2362
|
+
* version doesn't yet know. Preserving the raw value keeps the breaking
|
|
2363
|
+
* `changedJurisdiction` diff correct under a downgrade — coercing an unknown
|
|
2364
|
+
* value to `undefined` would fail OPEN and hide the most destructive change.
|
|
2365
|
+
*/
|
|
2366
|
+
jurisdiction?: string;
|
|
1245
2367
|
/** Sorted list of every declared `defineMigration` id at capture time. */
|
|
1246
2368
|
migrationIds: ReadonlyArray<string>;
|
|
1247
2369
|
/** Table name → {@link TableSnapshot}, keys sorted for stable serialization. */
|
|
@@ -1255,7 +2377,7 @@ interface DriftChange {
|
|
|
1255
2377
|
/** Human-readable, actionable description (used in the gate message). */
|
|
1256
2378
|
summary: string;
|
|
1257
2379
|
/** A machine-readable change discriminator. */
|
|
1258
|
-
type: "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedFieldKind" | "changedIndex" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "removedField" | "removedIndex" | "removedRelation" | "removedTable";
|
|
2380
|
+
type: "addedIndex" | "addedOptionalField" | "addedRelation" | "addedRequiredField" | "addedTable" | "changedJurisdiction" | "changedFieldKind" | "changedIndex" | "changedShardMode" | "fieldOptionalToRequired" | "fieldRequiredToOptional" | "removedField" | "removedIndex" | "removedRelation" | "removedTable";
|
|
1259
2381
|
}
|
|
1260
2382
|
/** The result of diffing two snapshots: every classified change. */
|
|
1261
2383
|
interface SchemaDrift {
|
|
@@ -1276,8 +2398,8 @@ declare const serializeSchemaSnapshot: (snapshot: SchemaSnapshot) => string;
|
|
|
1276
2398
|
* treat a corrupt baseline as a hard error rather than silently degrading to a
|
|
1277
2399
|
* "first capture" that would mask drift and then overwrite the bad file.
|
|
1278
2400
|
*/
|
|
1279
|
-
declare class SchemaSnapshotParseError extends
|
|
1280
|
-
|
|
2401
|
+
declare class SchemaSnapshotParseError extends LunoraError {
|
|
2402
|
+
constructor(message: string);
|
|
1281
2403
|
}
|
|
1282
2404
|
/**
|
|
1283
2405
|
* Parse a committed snapshot file. Returns `undefined` ONLY when the content is
|
|
@@ -1357,6 +2479,11 @@ declare const refreshCodegenProject: (project: Project, lunoraDirectory: string)
|
|
|
1357
2479
|
* Top-level codegen entry. Parses `<projectRoot>/lunora/schema.ts` and every
|
|
1358
2480
|
* function file under `<projectRoot>/lunora/`, then writes
|
|
1359
2481
|
* `_generated/{api,server,dataModel}.ts` next to them.
|
|
2482
|
+
*
|
|
2483
|
+
* When `LUNORA_CODEGEN_TIMING` is set (truthy), a single diagnostic summary
|
|
2484
|
+
* line is written to stderr with the total wall time and the discovery-vs-emit
|
|
2485
|
+
* split — opt-in instrumentation that is otherwise zero-cost and side-effect-free
|
|
2486
|
+
* on the returned {@link CodegenResult}.
|
|
1360
2487
|
*/
|
|
1361
2488
|
declare const runCodegen: (options: CodegenOptions) => CodegenResult;
|
|
1362
2489
|
interface CodegenOptions {
|
|
@@ -1407,6 +2534,14 @@ interface CodegenOptions {
|
|
|
1407
2534
|
* a breaking change. Ignored when `dryRun` is true.
|
|
1408
2535
|
*/
|
|
1409
2536
|
updateSchemaBaseline?: boolean;
|
|
2537
|
+
/**
|
|
2538
|
+
* Committed `wrangler.jsonc` `vars` entries that hold plaintext secrets — the
|
|
2539
|
+
* `plaintext_secret_in_wrangler_vars` lint input. Produced by `@lunora/config`
|
|
2540
|
+
* (which reads `wrangler.jsonc`) and threaded through by the CLI / Vite plugin;
|
|
2541
|
+
* codegen only forwards it to the advisor. Absent when no wrangler config is
|
|
2542
|
+
* present or the caller doesn't scan it.
|
|
2543
|
+
*/
|
|
2544
|
+
wranglerVariables?: ReadonlyArray<WranglerVariableIR>;
|
|
1410
2545
|
}
|
|
1411
2546
|
interface CodegenResult {
|
|
1412
2547
|
/**
|
|
@@ -1433,6 +2568,8 @@ interface CodegenResult {
|
|
|
1433
2568
|
generated: {
|
|
1434
2569
|
api: string; /** Fluent worker-composition builder (`_generated/app.ts`) — `defineApp()`. Always written. */
|
|
1435
2570
|
app: string;
|
|
2571
|
+
/** Partial-replication collection factories (`_generated/collections.ts`); `""` (and not written) unless the project declares shapes and installs `@lunora/db`. */
|
|
2572
|
+
collections: string;
|
|
1436
2573
|
/** Container DO classes (`_generated/containers.ts`); `""` (and not written) when no containers are declared. */
|
|
1437
2574
|
containers: string;
|
|
1438
2575
|
crons: string;
|
|
@@ -1457,6 +2594,8 @@ interface CodegenResult {
|
|
|
1457
2594
|
* `apiSpec` includes `openrpc`.
|
|
1458
2595
|
*/
|
|
1459
2596
|
openRpcModule: string;
|
|
2597
|
+
/** Push-consumer queue registry (`_generated/queues.ts`); `""` (and not written) when no push queues are declared. */
|
|
2598
|
+
queues: string;
|
|
1460
2599
|
/** Project-bound seed client (`_generated/seed.ts`); `""` (and not written) when `@lunora/seed` is not a declared dependency. */
|
|
1461
2600
|
seed: string;
|
|
1462
2601
|
server: string;
|
|
@@ -1467,6 +2606,13 @@ interface CodegenResult {
|
|
|
1467
2606
|
};
|
|
1468
2607
|
outputDirectory: string;
|
|
1469
2608
|
/**
|
|
2609
|
+
* Queues discovered from `defineQueue` exports in `lunora/queues.ts` — the
|
|
2610
|
+
* list the config layer reconciles into wrangler's `queues.producers[]` /
|
|
2611
|
+
* `queues.consumers[]`. Queues are NOT Durable Objects, so this adds no
|
|
2612
|
+
* binding or migration. Empty when the project declares no queues.
|
|
2613
|
+
*/
|
|
2614
|
+
queues: ReadonlyArray<QueueIR>;
|
|
2615
|
+
/**
|
|
1470
2616
|
* The CURRENT structural schema snapshot computed this run (tables + field
|
|
1471
2617
|
* kinds/optionality + indexes/relations/shard mode + declared migration ids).
|
|
1472
2618
|
* The pre-deploy drift gate diffs this against the committed baseline read
|
|
@@ -1510,5 +2656,9 @@ declare const validatorIrToJsonSchema: (validator: ValidatorIR) => JsonSchema;
|
|
|
1510
2656
|
* the contract; clients switch on `error.code`. Kept sorted for stable output.
|
|
1511
2657
|
*/
|
|
1512
2658
|
declare const LUNORA_ERROR_CODES: ReadonlyArray<string>;
|
|
2659
|
+
/** The matching secret rule's `kind` for a string value, or `undefined` when none matches. */
|
|
2660
|
+
declare const secretKindOf: (value: string) => string | undefined;
|
|
2661
|
+
/** A redacted preview of a secret value — first 4 chars plus its length, never the full value. */
|
|
2662
|
+
declare const redact: (value: string) => string;
|
|
1513
2663
|
declare const VERSION = "0.0.0";
|
|
1514
|
-
export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, type FieldSnapshot, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, type MaskProcedureIR, type MigrationIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, type QueryReadIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverNondeterministicCalls, discoverQueries, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, formatAdvisories, lintSchema, parseSchemaSnapshot, refreshCodegenProject, runCodegen, schemaFromIr, serializeSchemaSnapshot, validatorIrToJsonSchema };
|
|
2664
|
+
export { type AuthApiCallIR, CONTAINERS_FILENAME, CodegenDiagnosticError, type CodegenOptions, type CodegenResult, type ContainerIR, type CronJobIR, type DriftChange, type EmitAppOptions, FLAGS_FILENAME, type FieldSnapshot, type FlagsIR, type FunctionIR, GENERATED_HEADER, type HttpRouteIR, type IndexIR, type IndexSnapshot, type InsertWriteIR, LUNORA_ERROR_CODES, type LintSchemaOptions, MUTATORS_FILENAME, type MaskProcedureIR, type MigrationIR, type MutatorIR, OPENRPC_VERSION, type OpenApiEmitInput, type OpenRpcEmitInput, type ProjectIR, QUEUES_FILENAME, type QueryReadIR, type QueueIR, type R2sqlCallIR, type RelationSnapshot, type RlsMetadataIR, type RlsPolicyIR, type RlsProcedureIR, type RlsRoleIR, SCHEMA_SNAPSHOT_FILENAME, SCHEMA_SNAPSHOT_VERSION, SHAPES_FILENAME, type SchemaDrift, type SchemaDriftDecision, type SchemaIR, type SchemaSnapshot, SchemaSnapshotParseError, type ShapeIR, type StorageRuleIR, type StorageRulesMetadataIR, type TableIR, type TableSnapshot, VERSION, type ValidatorIR, type VectorIndexIR, WORKFLOWS_FILENAME, type WorkflowIR, type WranglerVariableIR, buildOpenApiDocument, buildOpenRpcDocument, buildSchemaSnapshot, createCodegenProject, diagnosticAt, diffSchemaSnapshots, discoverAuthApiCalls, discoverContainers, discoverCrons, discoverFlags, discoverFunctions, discoverHttpRoutes, discoverInserts, discoverMaskProcedures, discoverMigrations, discoverMutators, discoverNondeterministicCalls, discoverQueries, discoverQueues, discoverR2sqlCalls, discoverRlsMetadata, discoverRlsProcedures, discoverSchema, discoverShapes, discoverStorageRulesMetadata, discoverWorkflows, emitApi, emitApp, emitCollections, emitContainers, emitCrons, emitDataModel, emitDrizzleSchema, emitFunctions, emitOpenApi, emitOpenApiModule, emitOpenRpc, emitOpenRpcModule, emitServer, emitShard, emitVectors, emitWorkflows, emitWranglerCronTriggers, evaluateSchemaDrift, formatAdvisories, lintSchema, parseSchemaSnapshot, redact, refreshCodegenProject, runCodegen, schemaFromIr, secretKindOf, serializeSchemaSnapshot, validatorIrToJsonSchema };
|