@lunora/codegen 1.0.0-alpha.3 → 1.0.0-alpha.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/__assets__/package-og.svg +1 -1
  2. package/dist/index.d.mts +1084 -25
  3. package/dist/index.d.ts +1084 -25
  4. package/dist/index.mjs +29 -23
  5. package/dist/packem_shared/{CONTAINERS_FILENAME-0K-pjNb8.mjs → CONTAINERS_FILENAME-DjpXMqhp.mjs} +1 -1
  6. package/dist/packem_shared/{CodegenDiagnosticError-54jWDxA9.mjs → CodegenDiagnosticError-DyQ5FwkM.mjs} +7 -5
  7. package/dist/packem_shared/FLAGS_FILENAME-BjpS5w08.mjs +139 -0
  8. package/dist/packem_shared/{GENERATED_HEADER-CuLyj0WQ.mjs → GENERATED_HEADER-f6nMvllu.mjs} +853 -65
  9. package/dist/packem_shared/MUTATORS_FILENAME-BZOfUhlY.mjs +81 -0
  10. package/dist/packem_shared/{OPENRPC_VERSION-BGUrsrt_.mjs → OPENRPC_VERSION-u5SqDDGk.mjs} +1 -1
  11. package/dist/packem_shared/QUEUES_FILENAME-BF0iUmx7.mjs +119 -0
  12. package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-Ca-TlVEc.mjs +3481 -0
  13. package/dist/packem_shared/{SCHEMA_SNAPSHOT_VERSION-DzLDbWk3.mjs → SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs} +18 -2
  14. package/dist/packem_shared/SHAPES_FILENAME-DOhPGi-6.mjs +94 -0
  15. package/dist/packem_shared/{WORKFLOWS_FILENAME-DRDQdhfq.mjs → WORKFLOWS_FILENAME-CCC_42o3.mjs} +42 -2
  16. package/dist/packem_shared/{buildOpenApiDocument-CXwnbp4b.mjs → buildOpenApiDocument-AgKWmlry.mjs} +1 -1
  17. package/dist/packem_shared/{discoverAuthApiCalls-C35R6z0T.mjs → discoverAuthApiCalls-URDoTADN.mjs} +1 -1
  18. package/dist/packem_shared/{discoverCrons-BL6iGuJ3.mjs → discoverCrons-DdZOeroL.mjs} +20 -17
  19. package/dist/packem_shared/{discoverFunctions-DEgAcRuD.mjs → discoverFunctions-BJdF7lRs.mjs} +63 -9
  20. package/dist/packem_shared/{discoverHttpRoutes-C978pBiG.mjs → discoverHttpRoutes-CcwP-Rkr.mjs} +2 -2
  21. package/dist/packem_shared/{discoverInserts-CRQdXvHO.mjs → discoverInserts-BpFhM32L.mjs} +24 -2
  22. package/dist/packem_shared/{discoverMaskProcedures-B64zA740.mjs → discoverMaskProcedures-DT-v8wvj.mjs} +58 -2
  23. package/dist/packem_shared/{discoverMigrations-Doj_-BAA.mjs → discoverMigrations-cG1idBVM.mjs} +10 -4
  24. package/dist/packem_shared/{discoverNondeterministicCalls-4KiPQxQU.mjs → discoverNondeterministicCalls-CEOjmfk4.mjs} +1 -1
  25. package/dist/packem_shared/{discoverQueries-BkIi0dBD.mjs → discoverQueries-DeVBQVAG.mjs} +1 -1
  26. package/dist/packem_shared/{discoverR2sqlCalls-BpDqvcUn.mjs → discoverR2sqlCalls-CWCAU-xJ.mjs} +1 -1
  27. package/dist/packem_shared/{discoverRlsMetadata-DpRB1HMe.mjs → discoverRlsMetadata-BL0oukaK.mjs} +1 -1
  28. package/dist/packem_shared/{discoverSchema-BBulgGbH.mjs → discoverSchema-CeXJWVKV.mjs} +349 -17
  29. package/dist/packem_shared/{discoverStorageRulesMetadata-DAqJUxUv.mjs → discoverStorageRulesMetadata-CFHByjIl.mjs} +1 -1
  30. package/dist/packem_shared/{emitApp-CzSxVDaG.mjs → emitApp-BUCrHOeI.mjs} +94 -8
  31. package/dist/packem_shared/{formatAdvisories-8NIv1k0I.mjs → formatAdvisories-C9wNBNvL.mjs} +47 -3
  32. package/dist/packem_shared/{parse-validator-tuQtHrsr.mjs → parse-validator-D6zI2i85.mjs} +5 -3
  33. package/dist/packem_shared/redact-oTmsol5A.mjs +33 -0
  34. package/package.json +9 -7
  35. package/dist/packem_shared/SCHEMA_SNAPSHOT_FILENAME-BQ_kCZ81.mjs +0 -903
@@ -1,4 +1,4 @@
1
- import { GENERATED_HEADER } from './GENERATED_HEADER-CuLyj0WQ.mjs';
1
+ import { GENERATED_HEADER } from './GENERATED_HEADER-f6nMvllu.mjs';
2
2
 
3
3
  const LONG_TAIL = [
4
4
  ["hasAi", "ai", "ai", "Override the Workers AI binding backing `ctx.ai` (defaults to `env.AI`)."],
@@ -22,8 +22,28 @@ const LONG_TAIL = [
22
22
  ["hasVectors", "vectors", "vectors", "Wire the Vectorize index map backing `ctx.vectors`."]
23
23
  ];
24
24
  const hasAnyLongTail = (options) => LONG_TAIL.some(([flag]) => options[flag]);
25
+ const buildIdentityImports = (identity) => identity ? [`import * as lunoraIdentityContract from "../identity.js";`] : [];
26
+ const buildAccessImports = (hasAccess, hasAuth) => hasAccess ? [
27
+ `import type { CreateAccessResolverOptions } from "@lunora/cloudflare-access";`,
28
+ `import { createAccessResolver${hasAuth ? ", composeResolvers" : ""} } from "@lunora/cloudflare-access";`
29
+ ] : [];
30
+ const buildKvImports = (hasKv) => hasKv ? [`import { createKvIntrospectorFromEnv } from "@lunora/bindings/kv";`] : [];
25
31
  const buildImportLines = (options) => {
26
- const { hasAuth, hasFramework, hasGlobal, hasHyperdriveGlobal, hasScheduler, hasStorage, hasWorkflow, useUmbrella, wantsOpenApi, wantsOpenRpc } = options;
32
+ const {
33
+ hasAccess,
34
+ hasAuth,
35
+ hasFramework,
36
+ hasGlobal,
37
+ hasHyperdriveGlobal,
38
+ hasKv,
39
+ hasQueue,
40
+ hasScheduler,
41
+ hasStorage,
42
+ hasWorkflow,
43
+ useUmbrella,
44
+ wantsOpenApi,
45
+ wantsOpenRpc
46
+ } = options;
27
47
  const runtimeModule = useUmbrella ? "lunorash/runtime" : "@lunora/runtime";
28
48
  const runtimeTypeImports = ["ExecutionContextLike", "LunoraWorker", "Route", "ScheduledControllerLike", "ShardNamespaceLike", "WorkerOptions"];
29
49
  if (hasGlobal) {
@@ -42,6 +62,7 @@ const buildImportLines = (options) => {
42
62
  `import type { LunoraAuth, LunoraAuthOptions } from "@lunora/auth";`,
43
63
  `import { createAuth, createAuthAdmin, ensureMigrated, handleAuthRequest, lunoraD1Adapter } from "@lunora/auth";`
44
64
  ] : [],
65
+ ...buildAccessImports(hasAccess, hasAuth),
45
66
  ...hasGlobal ? [
46
67
  `import type { D1CtxDbOptions, D1DatabaseLike, D1Exec } from "@lunora/d1";`,
47
68
  `import { createD1CtxDb, facetGlobalColumn, listGlobalTables, readGlobalTablePage } from "@lunora/d1";`
@@ -51,15 +72,21 @@ const buildImportLines = (options) => {
51
72
  `import { createHyperdriveGlobalCtxDb } from "@lunora/hyperdrive/global";`,
52
73
  `import type { SqlCtxDbOptions, SqlExec } from "@lunora/sql-store";`
53
74
  ] : [],
75
+ ...buildKvImports(hasKv),
54
76
  ...hasScheduler ? [`import type { DurableObjectNamespaceLike } from "@lunora/scheduler";`, `import { createScheduler } from "@lunora/scheduler";`] : [],
55
77
  ...hasStorage ? [`import type { R2BucketLike, Storage } from "@lunora/storage";`, `import { createBucketStorage, createStorage } from "@lunora/storage";`] : [],
56
78
  ...hasWorkflow ? [`import { createWorkflowsRestClient } from "@lunora/workflow";`] : [],
57
79
  `import type { ${[...runtimeTypeImports].toSorted((a, b) => a.localeCompare(b)).join(", ")} } from "${runtimeModule}";`,
58
80
  `import { ${runtimeValueImports} } from "${runtimeModule}";`,
59
81
  ``,
82
+ ...buildIdentityImports(options.identity),
60
83
  ...hasGlobal || hasHyperdriveGlobal ? [`import schema from "../schema.js";`] : [],
61
84
  `import { LUNORA_CRONS } from "./crons.js";`,
62
85
  `import { LUNORA_FUNCTIONS } from "./functions.js";`,
86
+ ...hasQueue ? [
87
+ `import { createQueueCaptureSink, dispatchQueueBatch, shouldCaptureQueue } from "@lunora/queue";`,
88
+ `import { LUNORA_QUEUE_REGISTRY } from "./queues.js";`
89
+ ] : [],
63
90
  ...wantsOpenApi ? [`import { openApiSpec } from "./openapi.js";`] : [],
64
91
  ...wantsOpenRpc ? [`import { openRpcSpec } from "./openrpc.js";`] : [],
65
92
  `import { createShardDO } from "./shard.js";`
@@ -119,9 +146,10 @@ interface AuthDeclaration<Env> {
119
146
  ] : []
120
147
  ];
121
148
  const buildFieldLines = (options) => [
149
+ ...options.hasAccess ? [` private accessSelector?: Selector<Env, CreateAccessResolverOptions>;`] : [],
122
150
  ` private adminToken?: Selector<Env, string>;`,
123
151
  ...options.hasAuth ? [` private authDeclaration?: AuthDeclaration<Env>;`] : [],
124
- ` private readonly extendFns: ((env: Env) => Partial<WorkerOptions>)[] = [];`,
152
+ ` private readonly extendFns: ((env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>)[] = [];`,
125
153
  ...options.hasGlobal ? [` private globalDeclaration?: GlobalDeclaration<Env>;`] : [],
126
154
  ...options.hasHyperdriveGlobal ? [` private hyperdriveGlobalDeclaration?: HyperdriveGlobalDeclaration<Env>;`] : [],
127
155
  ` private readonly routeMap: Record<string, Route> = {};`,
@@ -139,6 +167,14 @@ const buildLongTailMethods = (options) => LONG_TAIL.filter(([flag]) => options[f
139
167
  }`
140
168
  );
141
169
  const buildMethodBlocks = (options) => [
170
+ ...options.hasAccess ? [
171
+ ` /** Wire Cloudflare Access (Zero Trust) — verifies the \`Cf-Access-Jwt-Assertion\` JWT and feeds the identity into \`ctx.auth\` / RLS via \`resolveIdentity\`. When \`.auth(...)\` is also configured, Access is composed ahead of it (Access wins when its JWT is present; everyone else falls through to the app session). */
172
+ public access(selector: Selector<Env, CreateAccessResolverOptions>): this {
173
+ this.accessSelector = selector;
174
+
175
+ return this;
176
+ }`
177
+ ] : [],
142
178
  ` /** Bearer token gating the \`/_lunora/admin/*\` endpoints the studio calls. */
143
179
  public admin(selector: Selector<Env, string>): this {
144
180
  this.adminToken = selector;
@@ -153,8 +189,8 @@ const buildMethodBlocks = (options) => [
153
189
  return this;
154
190
  }`
155
191
  ] : [],
156
- ` /** Escape hatch — merge raw \`WorkerOptions\` (anything not yet sugared) over the derived options at build time. */
157
- public extend(fn: (env: Env) => Partial<WorkerOptions>): this {
192
+ ` /** Escape hatch — merge raw \`WorkerOptions\` (anything not yet sugared) over the derived options at build time. The second \`derived\` argument is a snapshot of the options assembled so far (after \`.auth(...)\` etc.), so you can compose rather than clobber — e.g. wrap \`derived.resolveIdentity\` instead of replacing it. */
193
+ public extend(fn: (env: Env, derived: Readonly<WorkerOptions>) => Partial<WorkerOptions>): this {
158
194
  this.extendFns.push(fn);
159
195
 
160
196
  return this;
@@ -274,7 +310,7 @@ const buildShardFactoryBody = (options) => {
274
310
  const namespace = this.schedulerDeclaration?.namespace(env);
275
311
  const origin = this.schedulerDeclaration?.origin?.(env);
276
312
 
277
- return namespace && origin ? createScheduler({ namespace, originUrl: origin }) : undefined;
313
+ return namespace && origin ? createScheduler({${options.jurisdiction ? ` jurisdiction: ${JSON.stringify(options.jurisdiction)},` : ""} namespace, originUrl: origin }) : undefined;
278
314
  },
279
315
  }
280
316
  : {}),`
@@ -321,6 +357,12 @@ const buildWorkerOptionLines = (options) => [
321
357
  Object.assign(options, this.buildStorageAdmin(env));
322
358
  }`
323
359
  ] : [],
360
+ // The studio's KV browser is wired zero-config: `createKvIntrospectorFromEnv`
361
+ // scans `env` for every bound Workers KV namespace, so each `kv_namespaces`
362
+ // entry in wrangler.jsonc appears under its binding name (any name, any count)
363
+ // with no manual `createKvIntrospector` call. A deployment with no KV binding
364
+ // yields an empty namespace list rather than crashing.
365
+ ...options.hasKv ? [` options.kvIntrospector = createKvIntrospectorFromEnv(env);`] : [],
324
366
  ...options.hasAuth ? [
325
367
  ` if (this.authDeclaration) {
326
368
  options.authHandler = (request) => {
@@ -343,13 +385,52 @@ const buildWorkerOptionLines = (options) => [
343
385
 
344
386
  options.authAdmin = authInstance ? createAuthAdmin(authInstance) : undefined;
345
387
  }`
388
+ ] : [],
389
+ // Cloudflare Access — runs AFTER the auth block so it can compose ahead of
390
+ // the better-auth resolver rather than clobber it. With `.auth()` present,
391
+ // a request carrying a verified Access JWT is authenticated by Access and
392
+ // everyone else falls through to the app session; without it, Access is the
393
+ // sole resolver.
394
+ ...options.hasAccess ? [
395
+ options.hasAuth ? ` if (this.accessSelector) {
396
+ const accessResolver = createAccessResolver(this.accessSelector(env));
397
+ const fallback = options.resolveIdentity;
398
+
399
+ options.resolveIdentity = fallback ? composeResolvers(accessResolver, fallback) : accessResolver;
400
+ }` : ` if (this.accessSelector) {
401
+ options.resolveIdentity = createAccessResolver(this.accessSelector(env));
402
+ }`
346
403
  ] : []
347
404
  ];
348
405
  const buildBaseWorkerOptions = (options) => [
349
406
  ` cronJobs: LUNORA_CRONS,`,
350
407
  ` functions: LUNORA_FUNCTIONS,`,
408
+ // The declared `defineIdentity(...)` contract — wires the runtime trust
409
+ // boundary so `wrapResolverWithContract` validates every resolved identity
410
+ // against it before it becomes `ctx.auth`. Emitted only when the app declares
411
+ // a contract, so apps without one keep unchanged output.
412
+ ...options.identity ? [` identity: lunoraIdentityContract.${options.identity.exportName},`] : [],
413
+ // Schema `.jurisdiction("…")` pins every DO the worker reaches to the
414
+ // Cloudflare data-residency region. Emitted only when declared, so apps
415
+ // without it keep the un-pinned global namespace (and unchanged output).
416
+ ...options.jurisdiction ? [` jurisdiction: ${JSON.stringify(options.jurisdiction)},`] : [],
351
417
  ...options.wantsOpenApi ? [` openApiSpec,`] : [],
352
418
  ...options.wantsOpenRpc ? [` openRpcSpec,`] : [],
419
+ // The push-consumer handler backing the worker's `queue(batch, …)` entry:
420
+ // routes each delivered batch to its `defineQueue` handler. Built from
421
+ // `@lunora/queue` here (keeping the runtime decoupled) and wired only when the
422
+ // app declares push queues in `lunora/queues.ts`. In a dev environment (or with
423
+ // `LUNORA_QUEUE_CAPTURE`), every consumed message is recorded into the studio's
424
+ // Queues log via the root shard's `recordQueueMessage` admin RPC.
425
+ ...options.hasQueue ? [
426
+ ` queue: (batch: unknown, queueEnv: unknown, _context: ExecutionContextLike): Promise<void> =>`,
427
+ ` dispatchQueueBatch(batch as Parameters<typeof dispatchQueueBatch>[0], LUNORA_QUEUE_REGISTRY, {`,
428
+ ` capture: shouldCaptureQueue(queueEnv as Record<string, unknown>)`,
429
+ ` ? createQueueCaptureSink(queueEnv as Record<string, unknown>${options.jurisdiction ? `, { jurisdiction: ${JSON.stringify(options.jurisdiction)} }` : ""})`,
430
+ ` : undefined,`,
431
+ ` env: queueEnv as Record<string, unknown>,`,
432
+ ` }),`
433
+ ] : [],
353
434
  ` routes: this.routeMap,`,
354
435
  ` shardDO: this.shardSelector?.(env) ?? (undefined as unknown as ShardNamespaceLike),`
355
436
  ];
@@ -558,7 +639,12 @@ ${buildWorkerLine}
558
639
  worker ??= buildWorker(rawEnv as Env);
559
640
 
560
641
  return worker.serverQuery(request, rawEnv, reference, args, options);
561
- },
642
+ },${options.hasQueue ? `
643
+ queue: async (batch: unknown, rawEnv: unknown, context: ExecutionContextLike): Promise<void> => {
644
+ worker ??= buildWorker(rawEnv as Env);
645
+
646
+ return worker.queue?.(batch, rawEnv, context);
647
+ },` : ""}
562
648
  };
563
649
 
564
650
  if (this.emailHandler) {
@@ -581,7 +667,7 @@ ${buildBaseWorkerOptions(options).join("\n")}
581
667
  }
582
668
 
583
669
  ${workerOptionLines.join("\n\n")}${workerOptionLines.length > 0 ? "\n\n" : ""} for (const fn of this.extendFns) {
584
- Object.assign(options, fn(env));
670
+ Object.assign(options, fn(env, { ...options }));
585
671
  }
586
672
 
587
673
  return options;
@@ -16,11 +16,19 @@ const flattenIndexes = (table) => [
16
16
  ];
17
17
  const toAdvisorSchema = (schema) => {
18
18
  return {
19
+ rlsMode: schema.rlsMode,
19
20
  tables: schema.tables.map((table) => {
20
21
  return {
21
22
  externallyManaged: table.externallyManaged ?? false,
23
+ externalSource: table.externalSource ? {
24
+ hasReconcile: table.externalSource.hasReconcile ?? false,
25
+ hasTenantBy: table.externalSource.hasTenantBy,
26
+ mode: table.externalSource.mode,
27
+ unanalyzable: table.externalSource.unanalyzable
28
+ } : void 0,
22
29
  fields: Object.keys(table.shape),
23
30
  indexes: flattenIndexes(table),
31
+ isPublic: table.isPublic ?? false,
24
32
  name: table.name,
25
33
  relations: table.relations.map((relation) => {
26
34
  return {
@@ -31,29 +39,65 @@ const toAdvisorSchema = (schema) => {
31
39
  references: relation.references,
32
40
  table: relation.table
33
41
  };
34
- })
42
+ }),
43
+ shardKind: typeof table.shardMode === "string" ? table.shardMode : "shardBy",
44
+ softDelete: table.softDelete
35
45
  };
36
46
  })
37
47
  };
38
48
  };
39
- const lintSchema = (schema, queries = [], inserts, authApiCalls, rlsProcedures, containers, workflows, workflowCalls, maskProcedures, nondeterministicCalls, procedureProtections, argumentValidators, secretLiterals, sqlInterpolations, adminRoutes, r2sqlCalls) => runAdvisor(
49
+ const toAdvisorShapes = (shapes) => shapes.map((shape) => {
50
+ return { exportName: shape.exportName, file: `lunora/${shape.filePath}.ts`, table: shape.table };
51
+ });
52
+ const lintSchema = (schema, queries = [], inserts, authApiCalls, rlsProcedures, containers, workflows, workflowCalls, maskProcedures, nondeterministicCalls, procedureProtections, argumentValidators, secretLiterals, sqlInterpolations, adminRoutes, r2sqlCalls, shapes, mutatorWrites, configCalls, argumentDerivedFetches, kvKeyAccesses, ownerFieldWrites, storageKeyAccesses, aiRawRuns, containerKeyAccesses, mailRecipientAccesses, vectorNamespaceAccesses, browserUrlAccesses, privilegedDispatches, containerOverrides, authConfigs, maskStrategies, imageDeliveryUrlAccesses, ratelimitKeySelectors, storageUploads, httpActionGuards, httpHeaderWrites, failOpenGuards, flagSecurityDefaults, aiToolSideEffects, identityClaimReads, paymentWebhooks, softDeleteReads, relationLoads, rawRowReturns, normalizeIdAuthorizations, wranglerVariables) => runAdvisor(
40
53
  {
41
54
  adminRoutes,
55
+ aiRawRuns,
56
+ aiToolSideEffects,
57
+ argumentDerivedFetches,
42
58
  argValidators: argumentValidators,
43
59
  authApiCalls,
60
+ authConfigs,
61
+ browserUrlAccesses,
62
+ configCalls,
63
+ containerKeyAccesses,
64
+ containerOverrides,
44
65
  containers,
66
+ failOpenGuards,
67
+ flagSecurityDefaults,
68
+ httpActionGuards,
69
+ httpHeaderWrites,
70
+ identityClaimReads,
71
+ imageDeliveryUrlAccesses,
45
72
  inserts,
73
+ kvKeyAccesses,
74
+ mailRecipientAccesses,
46
75
  maskProcedures,
76
+ maskStrategies,
77
+ mutatorWrites,
47
78
  nondeterministicCalls,
79
+ normalizeIdAuthorizations,
80
+ ownerFieldWrites,
81
+ paymentWebhooks,
82
+ privilegedDispatches,
48
83
  procedureProtections,
49
84
  queries,
50
85
  r2sqlCalls,
86
+ ratelimitKeySelectors,
87
+ rawRowReturns,
88
+ relationLoads,
51
89
  rlsProcedures,
52
90
  schema: toAdvisorSchema(schema),
53
91
  secretLiterals,
92
+ shapes: shapes === void 0 ? void 0 : toAdvisorShapes(shapes),
93
+ softDeleteReads,
54
94
  sqlInterpolations,
95
+ storageKeyAccesses,
96
+ storageUploads,
97
+ vectorNamespaceAccesses,
55
98
  workflowCalls,
56
- workflows
99
+ workflows,
100
+ wranglerVariables
57
101
  },
58
102
  { source: "static" }
59
103
  );
@@ -1,3 +1,4 @@
1
+ import { LunoraError } from '@lunora/errors';
1
2
  import { Node } from 'ts-morph';
2
3
 
3
4
  const FIELD_NAME_RE = /^[A-Za-z_$][\w$]*$/u;
@@ -53,7 +54,7 @@ const parseObjectShape = (object) => {
53
54
  }
54
55
  const fieldName = property.getName();
55
56
  if (!FIELD_NAME_RE.test(fieldName)) {
56
- throw new Error(`@lunora/codegen: field name is not a valid JS identifier: ${JSON.stringify(fieldName)}`);
57
+ throw new LunoraError("INTERNAL", `@lunora/codegen: field name is not a valid JS identifier: ${JSON.stringify(fieldName)}`);
57
58
  }
58
59
  out[fieldName] = parseValidator(initializer);
59
60
  }
@@ -106,7 +107,7 @@ const parseBuilderMember = (member, args) => {
106
107
  };
107
108
  }
108
109
  default: {
109
- throw new Error(`Unsupported validator kind: ${member}`);
110
+ throw new LunoraError("INTERNAL", `Unsupported validator kind: ${member}`);
110
111
  }
111
112
  }
112
113
  };
@@ -124,7 +125,8 @@ const parseValidatorCall = (call) => {
124
125
  }
125
126
  if (TRANSPARENT_MODIFIERS.has(member)) {
126
127
  const receiver = callee.getExpression();
127
- return Node.isExpression(receiver) ? parseValidator(receiver) : { kind: "any" };
128
+ const base = Node.isExpression(receiver) ? parseValidator(receiver) : { kind: "any" };
129
+ return member === "check" ? { ...base, hasRefinement: true } : base;
128
130
  }
129
131
  return parseBuilderMember(member, args);
130
132
  };
@@ -0,0 +1,33 @@
1
+ const HIGH_ENTROPY_TOKEN_RE = /[\w+/=-]{40,}/u;
2
+ const LOWER_RE = /[a-z]/u;
3
+ const UPPER_RE = /[A-Z]/u;
4
+ const DIGIT_RE = /\d/u;
5
+ const HEX_SECRET_RE = /\b(?:[\da-f]{32,}|[\dA-F]{32,})\b/u;
6
+ const isHighEntropy = (value) => {
7
+ const token = HIGH_ENTROPY_TOKEN_RE.exec(value)?.[0];
8
+ if (token === void 0) {
9
+ return false;
10
+ }
11
+ return LOWER_RE.test(token) && UPPER_RE.test(token) && DIGIT_RE.test(token);
12
+ };
13
+ const isHexSecret = (value) => HEX_SECRET_RE.test(value);
14
+ const STRIPE_LIVE_KEY_RE = /\b(?:sk|rk)_live_[\dA-Za-z]{20,}/u;
15
+ const AWS_ACCESS_KEY_RE = /\bAKIA[\dA-Z]{16}\b/u;
16
+ const GITHUB_TOKEN_RE = /\bgh[posru]_[\dA-Za-z]{36,}/u;
17
+ const OPENAI_KEY_RE = /\bsk-[\dA-Za-z]{32,}/u;
18
+ const SLACK_TOKEN_RE = /\bxox[abprs]-[\dA-Za-z-]{10,}/u;
19
+ const PRIVATE_KEY_RE = /-----BEGIN(?: [A-Z]+)? PRIVATE KEY-----/u;
20
+ const SECRET_RULES = [
21
+ { kind: "stripe_live_key", test: (value) => STRIPE_LIVE_KEY_RE.test(value) },
22
+ { kind: "aws_access_key", test: (value) => AWS_ACCESS_KEY_RE.test(value) },
23
+ { kind: "github_token", test: (value) => GITHUB_TOKEN_RE.test(value) },
24
+ { kind: "openai_key", test: (value) => OPENAI_KEY_RE.test(value) },
25
+ { kind: "slack_token", test: (value) => SLACK_TOKEN_RE.test(value) },
26
+ { kind: "private_key", test: (value) => PRIVATE_KEY_RE.test(value) },
27
+ { kind: "high_entropy", test: isHighEntropy },
28
+ { kind: "hex_secret", test: isHexSecret }
29
+ ];
30
+ const secretKindOf = (value) => SECRET_RULES.find((rule) => rule.test(value))?.kind;
31
+ const redact = (value) => `${value.slice(0, 4)}…(${String(value.length)} chars)`;
32
+
33
+ export { SECRET_RULES, redact, secretKindOf };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/codegen",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.0-alpha.31",
4
4
  "description": "Code generator for Lunora: emits _generated/{api,server,dataModel}.ts from your schema",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -25,7 +25,7 @@
25
25
  "directory": "packages/codegen"
26
26
  },
27
27
  "files": [
28
- "dist",
28
+ "./dist",
29
29
  "__assets__",
30
30
  "README.md",
31
31
  "LICENSE.md"
@@ -46,11 +46,13 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/advisor": "1.0.0-alpha.2",
50
- "@lunora/container": "1.0.0-alpha.1",
51
- "@lunora/scheduler": "1.0.0-alpha.1",
52
- "@lunora/values": "1.0.0-alpha.1",
53
- "@lunora/workflow": "1.0.0-alpha.1",
49
+ "@lunora/advisor": "1.0.0-alpha.17",
50
+ "@lunora/container": "1.0.0-alpha.6",
51
+ "@lunora/errors": "1.0.0-alpha.1",
52
+ "@lunora/queue": "1.0.0-alpha.4",
53
+ "@lunora/scheduler": "1.0.0-alpha.5",
54
+ "@lunora/values": "1.0.0-alpha.4",
55
+ "@lunora/workflow": "1.0.0-alpha.6",
54
56
  "ts-morph": "^28.0.0"
55
57
  },
56
58
  "engines": {