@lunora/codegen 1.0.0-alpha.51 → 1.0.0-alpha.53

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 (28) hide show
  1. package/dist/index.d.mts +66 -4
  2. package/dist/index.d.ts +66 -4
  3. package/dist/index.mjs +22 -21
  4. package/dist/packem_shared/{FLAGS_FILENAME-Dg4mKUuz.mjs → FLAGS_FILENAME-D5igzqwR.mjs} +1 -1
  5. package/dist/packem_shared/{GENERATED_HEADER-C5paWNYO.mjs → GENERATED_HEADER-C8tAvxqP.mjs} +1 -1
  6. package/dist/packem_shared/NOTIFY_FILENAME-CK2IrsrP.mjs +152 -0
  7. package/dist/packem_shared/{OPENRPC_VERSION-7A2weq2u.mjs → OPENRPC_VERSION-DvDChMhC.mjs} +1 -1
  8. package/dist/packem_shared/{SCHEMA_SNAPSHOT_FILENAME-G5dkcxPR.mjs → SCHEMA_SNAPSHOT_FILENAME--TKFIHmr.mjs} +118 -23
  9. package/dist/packem_shared/{buildOpenApiDocument-B7mEdzA2.mjs → buildOpenApiDocument-DCQSLuFc.mjs} +80 -1
  10. package/dist/packem_shared/{discoverAuthApiCalls-Dx3K42rk.mjs → discoverAuthApiCalls-Dhwgf4J4.mjs} +1 -1
  11. package/dist/packem_shared/{discoverCrons-DvqkEWdx.mjs → discoverCrons-UbQLLmMS.mjs} +1 -1
  12. package/dist/packem_shared/{discoverFunctions-BJ-qR7Rg.mjs → discoverFunctions-COG_Xkyz.mjs} +27 -1
  13. package/dist/packem_shared/{discoverHttpRoutes-daCzuTe8.mjs → discoverHttpRoutes-CVXWZkzo.mjs} +2 -2
  14. package/dist/packem_shared/{discoverInserts-DI4q5NxE.mjs → discoverInserts-DdWnXmLS.mjs} +1 -1
  15. package/dist/packem_shared/{discoverMaskProcedures-BcTOEKNU.mjs → discoverMaskProcedures-BG58_fw3.mjs} +1 -1
  16. package/dist/packem_shared/{discoverMigrations-VNUFvCwr.mjs → discoverMigrations-Bw1U01zr.mjs} +1 -1
  17. package/dist/packem_shared/{discoverNondeterministicCalls-S0N2xLCq.mjs → discoverNondeterministicCalls-BbXEFZUT.mjs} +1 -1
  18. package/dist/packem_shared/{discoverQueries-CJnnnLpd.mjs → discoverQueries-CDmxu2ET.mjs} +1 -1
  19. package/dist/packem_shared/{discoverR2sqlCalls-pnpicWfz.mjs → discoverR2sqlCalls-Bn7QVv7J.mjs} +1 -1
  20. package/dist/packem_shared/{discoverRlsMetadata-DppniPUH.mjs → discoverRlsMetadata-D9uN35no.mjs} +1 -1
  21. package/dist/packem_shared/{discoverSandboxUsage-BUM2r90k.mjs → discoverSandboxUsage-B5jDU6Bt.mjs} +1 -1
  22. package/dist/packem_shared/{discoverSchema-BaSAvooG.mjs → discoverSchema-BJp5_T4o.mjs} +32 -1
  23. package/dist/packem_shared/{discoverStorageRulesMetadata-CnHl2rXD.mjs → discoverStorageRulesMetadata-BqMhuEjo.mjs} +1 -1
  24. package/dist/packem_shared/{emit-ClTbCLy4.mjs → emit-DIbr7U31.mjs} +103 -18
  25. package/dist/packem_shared/{emitApp-CzzrjVqH.mjs → emitApp-DbMM8iHe.mjs} +11 -2
  26. package/dist/packem_shared/{formatAdvisories-BmF7Mplc.mjs → formatAdvisories-Cans5TWS.mjs} +17 -1
  27. package/dist/packem_shared/{parse-validator-BSJo1HGP.mjs → parse-validator-BDGV8iue.mjs} +1 -1
  28. package/package.json +7 -7
@@ -3,35 +3,36 @@ import { join, dirname } from 'node:path';
3
3
  import { performance } from 'node:perf_hooks';
4
4
  import { LunoraError } from '@lunora/errors';
5
5
  import { Node, SyntaxKind, Project } from 'ts-morph';
6
- import { lintSchema } from './formatAdvisories-BmF7Mplc.mjs';
7
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall, inlineHandler as inlineHandler$1, procedureHandler, chainUsesWrappedCall, isDatabaseAccessor, chainHasStep, discoverFunctions } from './discoverFunctions-BJ-qR7Rg.mjs';
6
+ import { lintSchema } from './formatAdvisories-Cans5TWS.mjs';
7
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall, inlineHandler as inlineHandler$1, procedureHandler, chainUsesWrappedCall, isDatabaseAccessor, chainHasStep, discoverFunctions } from './discoverFunctions-COG_Xkyz.mjs';
8
8
  import { discoverAgents } from './AGENTS_FILENAME-Cxx7wiSs.mjs';
9
- import discoverAuthApiCalls from './discoverAuthApiCalls-Dx3K42rk.mjs';
9
+ import discoverAuthApiCalls from './discoverAuthApiCalls-Dhwgf4J4.mjs';
10
10
  import { discoverContainers } from './CONTAINERS_FILENAME-DjpXMqhp.mjs';
11
- import discoverCrons from './discoverCrons-DvqkEWdx.mjs';
11
+ import discoverCrons from './discoverCrons-UbQLLmMS.mjs';
12
12
  import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
13
- import { C as CAPABILITIES, n as buildStorageColumns, f as emitDataModel, a as emitApi, i as emitServer, h as emitFunctions, j as emitShard, b as emitCollections, c as emitContainers, l as emitWorkflows, e as emitAgents, o as emitQueues, d as emitCrons, k as emitVectors, g as emitDrizzleSchema, p as emitSeed, m as emitWranglerCronTriggers } from './emit-ClTbCLy4.mjs';
14
- import { discoverFlagKeys } from './FLAGS_FILENAME-Dg4mKUuz.mjs';
15
- import discoverHttpRoutes from './discoverHttpRoutes-daCzuTe8.mjs';
16
- import discoverInserts from './discoverInserts-DI4q5NxE.mjs';
17
- import discoverMaskProcedures, { discoverMaskStrategies, discoverMaskMetadata } from './discoverMaskProcedures-BcTOEKNU.mjs';
18
- import discoverMigrations from './discoverMigrations-VNUFvCwr.mjs';
13
+ import { C as CAPABILITIES, n as buildStorageColumns, f as emitDataModel, a as emitApi, i as emitServer, h as emitFunctions, j as emitShard, b as emitCollections, c as emitContainers, l as emitWorkflows, e as emitAgents, o as emitQueues, d as emitCrons, k as emitVectors, g as emitDrizzleSchema, p as emitSeed, m as emitWranglerCronTriggers } from './emit-DIbr7U31.mjs';
14
+ import { discoverFlagKeys } from './FLAGS_FILENAME-D5igzqwR.mjs';
15
+ import discoverHttpRoutes from './discoverHttpRoutes-CVXWZkzo.mjs';
16
+ import discoverInserts from './discoverInserts-DdWnXmLS.mjs';
17
+ import discoverMaskProcedures, { discoverMaskStrategies, discoverMaskMetadata } from './discoverMaskProcedures-BG58_fw3.mjs';
18
+ import discoverMigrations from './discoverMigrations-Bw1U01zr.mjs';
19
19
  import { MUTATORS_FILENAME, isDefineMutatorCallee, discoverMutators } from './MUTATORS_FILENAME-BZOfUhlY.mjs';
20
- import discoverNondeterministicCalls from './discoverNondeterministicCalls-S0N2xLCq.mjs';
21
- import discoverQueries from './discoverQueries-CJnnnLpd.mjs';
20
+ import discoverNondeterministicCalls from './discoverNondeterministicCalls-BbXEFZUT.mjs';
21
+ import { discoverNotifyConfig, discoverNotifyCalls } from './NOTIFY_FILENAME-CK2IrsrP.mjs';
22
+ import discoverQueries from './discoverQueries-CDmxu2ET.mjs';
22
23
  import { discoverQueues } from './QUEUES_FILENAME-Xv6Vy-Ku.mjs';
23
- import discoverR2sqlCalls from './discoverR2sqlCalls-pnpicWfz.mjs';
24
- import discoverRlsProcedures, { discoverRlsMetadata } from './discoverRlsMetadata-DppniPUH.mjs';
25
- import { discoverSandboxUsage } from './discoverSandboxUsage-BUM2r90k.mjs';
26
- import discoverSchema from './discoverSchema-BaSAvooG.mjs';
24
+ import discoverR2sqlCalls from './discoverR2sqlCalls-Bn7QVv7J.mjs';
25
+ import discoverRlsProcedures, { discoverRlsMetadata } from './discoverRlsMetadata-D9uN35no.mjs';
26
+ import { discoverSandboxUsage } from './discoverSandboxUsage-B5jDU6Bt.mjs';
27
+ import discoverSchema from './discoverSchema-BJp5_T4o.mjs';
27
28
  import { secretKindOf, redact } from './redact-oTmsol5A.mjs';
28
29
  import { discoverShapes } from './SHAPES_FILENAME-DOhPGi-6.mjs';
29
- import discoverStorageRulesMetadata from './discoverStorageRulesMetadata-CnHl2rXD.mjs';
30
+ import discoverStorageRulesMetadata from './discoverStorageRulesMetadata-BqMhuEjo.mjs';
30
31
  import { e as enclosingExportName$2 } from './discover-ast-CT6BgBr4.mjs';
31
32
  import { discoverWorkflows } from './WORKFLOWS_FILENAME-Dtuzvluc.mjs';
32
- import { emitApp } from './emitApp-CzzrjVqH.mjs';
33
- import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-B7mEdzA2.mjs';
34
- import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-7A2weq2u.mjs';
33
+ import { emitApp } from './emitApp-DbMM8iHe.mjs';
34
+ import { buildOpenApiDocument, emitOpenApiModule } from './buildOpenApiDocument-DCQSLuFc.mjs';
35
+ import { buildOpenRpcDocument, emitOpenRpcModule } from './OPENRPC_VERSION-DvDChMhC.mjs';
35
36
  import { buildSchemaSnapshot, serializeSchemaSnapshot } from './SCHEMA_SNAPSHOT_VERSION-D0ARY6rL.mjs';
36
37
 
37
38
  const HTTP_VERBS$1 = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
@@ -937,6 +938,62 @@ const discoverEnv = (project, lunoraDirectory) => {
937
938
  return environments[0];
938
939
  };
939
940
 
941
+ const SINK_FACTORIES = /* @__PURE__ */ new Set(["defineExportSink", "r2Sink", "webhookExportSink"]);
942
+ const sinkFactoryOf = (call) => {
943
+ const callee = call.getExpression();
944
+ if (!Node.isIdentifier(callee)) {
945
+ return void 0;
946
+ }
947
+ const name = callee.getText();
948
+ return SINK_FACTORIES.has(name) ? name : void 0;
949
+ };
950
+ const analyzeConfig = (literal) => {
951
+ const presentKeys = [];
952
+ const emptyKeys = [];
953
+ for (const property of literal.getProperties()) {
954
+ if (Node.isSpreadAssignment(property)) {
955
+ return { analyzable: false, emptyKeys: [], presentKeys: [] };
956
+ }
957
+ if (Node.isPropertyAssignment(property)) {
958
+ const key = property.getName();
959
+ presentKeys.push(key);
960
+ const initializer = property.getInitializer();
961
+ if (initializer && Node.isStringLiteral(initializer) && initializer.getLiteralText() === "") {
962
+ emptyKeys.push(key);
963
+ }
964
+ continue;
965
+ }
966
+ if (Node.isShorthandPropertyAssignment(property) || Node.isMethodDeclaration(property) || Node.isGetAccessorDeclaration(property)) {
967
+ presentKeys.push(property.getName());
968
+ }
969
+ }
970
+ return { analyzable: true, emptyKeys, presentKeys };
971
+ };
972
+ const discoverExportSinks = (project, lunoraDirectory) => {
973
+ const sinks = [];
974
+ for (const filePath of listLunoraSourceFiles(lunoraDirectory)) {
975
+ const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
976
+ const relativePath = lunoraRelativePath(lunoraDirectory, filePath);
977
+ for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
978
+ const factory = sinkFactoryOf(call);
979
+ if (factory === void 0) {
980
+ continue;
981
+ }
982
+ const argument = call.getArguments()[0];
983
+ const facts = argument && Node.isObjectLiteralExpression(argument) ? analyzeConfig(argument) : { analyzable: false, emptyKeys: [], presentKeys: [] };
984
+ sinks.push({
985
+ analyzable: facts.analyzable,
986
+ emptyKeys: facts.emptyKeys,
987
+ factory,
988
+ file: relativePath,
989
+ line: call.getStartLineNumber(),
990
+ presentKeys: facts.presentKeys
991
+ });
992
+ }
993
+ }
994
+ return sinks;
995
+ };
996
+
940
997
  const OPTIONS_ARGUMENT_INDEX$1 = /* @__PURE__ */ new Map([
941
998
  ["dbRateLimit", 2],
942
999
  ["rateLimit", 2],
@@ -1046,7 +1103,7 @@ const buildStudioFeatures = (usage, signals) => {
1046
1103
  flags: usage.flags || signals.dependencies.has("@lunora/flags"),
1047
1104
  kv: usage.kv || signals.dependencies.has("@lunora/bindings/kv"),
1048
1105
  mail: usage.mail || signals.dependencies.has("@lunora/mail"),
1049
- payments: usage.payments || signals.dependencies.has("@lunora/payment"),
1106
+ payments: usage.payments || signals.hasPaymentTables,
1050
1107
  queues: signals.queueCount > 0 || signals.dependencies.has("@lunora/queue"),
1051
1108
  scheduler: usage.scheduler || signals.cronCount > 0 || signals.dependencies.has("@lunora/scheduler"),
1052
1109
  storage: usage.storage || signals.storageRuleCount > 0 || signals.storageColumnCount > 0 || signals.dependencies.has("@lunora/storage"),
@@ -1106,6 +1163,29 @@ const discoverFlagSecurityDefaults = (project, lunoraDirectory) => {
1106
1163
  return flags;
1107
1164
  };
1108
1165
 
1166
+ const isWithGeoIndexCall = (call) => {
1167
+ const callee = call.getExpression();
1168
+ return Node.isPropertyAccessExpression(callee) && callee.getName() === "withGeoIndex";
1169
+ };
1170
+ const indexNameOf = (call) => {
1171
+ const argument = call.getArguments()[0];
1172
+ return argument && Node.isStringLiteral(argument) ? argument.getLiteralText() : "";
1173
+ };
1174
+ const discoverGeoIndexUsages = (project, lunoraDirectory) => {
1175
+ const usages = [];
1176
+ for (const filePath of listLunoraSourceFiles(lunoraDirectory)) {
1177
+ const sourceFile = project.getSourceFile(filePath) ?? project.addSourceFileAtPath(filePath);
1178
+ const relativePath = lunoraRelativePath(lunoraDirectory, filePath);
1179
+ for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
1180
+ if (!isWithGeoIndexCall(call)) {
1181
+ continue;
1182
+ }
1183
+ usages.push({ file: relativePath, indexName: indexNameOf(call), line: call.getStartLineNumber() });
1184
+ }
1185
+ }
1186
+ return usages;
1187
+ };
1188
+
1109
1189
  const HTTP_VERBS = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
1110
1190
  const TERMINAL_STEPS = /* @__PURE__ */ new Set(["handler", "stream"]);
1111
1191
  const RUN_SIDE_EFFECTS = /* @__PURE__ */ new Set(["runAction", "runMutation"]);
@@ -2233,6 +2313,7 @@ const discoverPrivilegedDispatches = (project, lunoraDirectory) => {
2233
2313
 
2234
2314
  const MIDDLEWARE_FLAGS = {
2235
2315
  dbRateLimit: "usesRateLimit",
2316
+ emailGateMiddleware: "usesEmailGate",
2236
2317
  mask: "usesMask",
2237
2318
  rateLimit: "usesRateLimit",
2238
2319
  rls: "usesRls",
@@ -2268,7 +2349,7 @@ const resolveUseArgumentCall = (argument) => {
2268
2349
  const initializer = declaration?.getInitializer();
2269
2350
  return initializer && Node.isCallExpression(initializer) ? initializer : void 0;
2270
2351
  };
2271
- const NO_PROTECTIONS = { usesCaptcha: false, usesMask: false, usesRateLimit: false, usesRls: false };
2352
+ const NO_PROTECTIONS = { usesCaptcha: false, usesEmailGate: false, usesMask: false, usesRateLimit: false, usesRls: false };
2272
2353
  const useStepProtections = (useArgument) => {
2273
2354
  const argument = resolveUseArgumentCall(useArgument);
2274
2355
  const name = argument ? calleeNameOf(argument) : void 0;
@@ -2293,6 +2374,7 @@ const protectionsInChain = (receiver) => {
2293
2374
  if (useArgument) {
2294
2375
  const step = useStepProtections(useArgument);
2295
2376
  protections.usesCaptcha ||= step.usesCaptcha;
2377
+ protections.usesEmailGate ||= step.usesEmailGate;
2296
2378
  protections.usesMask ||= step.usesMask;
2297
2379
  protections.usesRateLimit ||= step.usesRateLimit;
2298
2380
  protections.usesRls ||= step.usesRls;
@@ -2397,7 +2479,7 @@ const middlewareIrFromDeclaration = (declaration, relativePath) => {
2397
2479
  if (!classified || classified.kind !== "query" && classified.kind !== "mutation" && classified.kind !== "action") {
2398
2480
  return void 0;
2399
2481
  }
2400
- const protections = classified.receiver ? protectionsInChain(classified.receiver) : { usesCaptcha: false, usesMask: false, usesRateLimit: false, usesRls: false };
2482
+ const protections = classified.receiver ? protectionsInChain(classified.receiver) : { usesCaptcha: false, usesEmailGate: false, usesMask: false, usesRateLimit: false, usesRls: false };
2401
2483
  const { callsMail, fanOut, unboundedAiGeneration, usesInsertManyUnsafe, writesUserTable } = behaviourOf(declaration);
2402
2484
  return {
2403
2485
  callsMail,
@@ -2407,6 +2489,7 @@ const middlewareIrFromDeclaration = (declaration, relativePath) => {
2407
2489
  kind: classified.kind,
2408
2490
  unboundedAiGeneration,
2409
2491
  usesCaptcha: protections.usesCaptcha,
2492
+ usesEmailGate: protections.usesEmailGate,
2410
2493
  usesInsertManyUnsafe,
2411
2494
  usesMask: protections.usesMask,
2412
2495
  usesRateLimit: protections.usesRateLimit,
@@ -3223,8 +3306,10 @@ const runCodegen = (options) => {
3223
3306
  containerKeyAccesses: discoverContainerKeyAccesses(project, lunoraDirectory),
3224
3307
  containerOverrides: discoverContainerOverrides(project, lunoraDirectory),
3225
3308
  containers,
3309
+ exportSinks: discoverExportSinks(project, lunoraDirectory),
3226
3310
  failOpenGuards: discoverFailOpenGuards(project, lunoraDirectory),
3227
3311
  flagSecurityDefaults: discoverFlagSecurityDefaults(project, lunoraDirectory),
3312
+ geoIndexUsages: discoverGeoIndexUsages(project, lunoraDirectory),
3228
3313
  httpActionGuards: discoverHttpActionGuards(project, lunoraDirectory),
3229
3314
  httpHeaderWrites: discoverHttpHeaderWrites(project, lunoraDirectory),
3230
3315
  identityClaimReads: discoverIdentityClaimReads(project, lunoraDirectory),
@@ -3237,6 +3322,8 @@ const runCodegen = (options) => {
3237
3322
  mutatorWrites: discoverMutatorWrites(project, lunoraDirectory),
3238
3323
  nondeterministicCalls: discoverNondeterministicCalls(project, lunoraDirectory),
3239
3324
  normalizeIdAuthorizations: discoverNormalizeIdAuthorization(project, lunoraDirectory),
3325
+ notifyCalls: discoverNotifyCalls(project, lunoraDirectory),
3326
+ notifyConfig: discoverNotifyConfig(project, lunoraDirectory),
3240
3327
  ownerFieldWrites: discoverOwnerFieldWrites(project, lunoraDirectory),
3241
3328
  paymentWebhooks: discoverPaymentWebhooks(project, lunoraDirectory),
3242
3329
  privilegedDispatches: discoverPrivilegedDispatches(project, lunoraDirectory),
@@ -3270,6 +3357,7 @@ const runCodegen = (options) => {
3270
3357
  const hasAccessFacade = featureUsage.access;
3271
3358
  const hasFlags = existsSync(join(lunoraDirectory, "flags.ts"));
3272
3359
  const flagKeys = hasFlags ? discoverFlagKeys(project, lunoraDirectory) : [];
3360
+ const hasNotify = existsSync(join(lunoraDirectory, "notify.ts"));
3273
3361
  const hasHyperdrive = featureUsage.hyperdrive;
3274
3362
  const sandboxUsage = discoverSandboxUsage(project, lunoraDirectory);
3275
3363
  const usesSandbox = sandboxUsage.usesSandboxBrowser || sandboxUsage.usesSandboxContainer;
@@ -3284,6 +3372,10 @@ const runCodegen = (options) => {
3284
3372
  containerCount: containers.length,
3285
3373
  cronCount: crons.length,
3286
3374
  dependencies,
3375
+ // Payments gates on the store tables the panel reads being declared, not on a
3376
+ // bare `@lunora/payment` dependency (which may be present only to reuse the
3377
+ // package's pure webhook helpers) — see the payment-tables signal set below.
3378
+ hasPaymentTables: schema.tables.some((table) => table.name === "subscriptions") && schema.tables.some((table) => table.name === "events"),
3287
3379
  queueCount: queues.length,
3288
3380
  storageColumnCount: Object.keys(buildStorageColumns(schema)).length,
3289
3381
  storageRuleCount: storageRulesMetadata.rules.length,
@@ -3306,6 +3398,7 @@ const runCodegen = (options) => {
3306
3398
  hasHyperdrive,
3307
3399
  hasImages,
3308
3400
  hasKv,
3401
+ hasNotify,
3309
3402
  hasPayments,
3310
3403
  hasPipelines,
3311
3404
  hasR2sql,
@@ -3332,6 +3425,7 @@ const runCodegen = (options) => {
3332
3425
  hasHyperdrive,
3333
3426
  hasImages,
3334
3427
  hasKv,
3428
+ hasNotify,
3335
3429
  hasPayments,
3336
3430
  hasPipelines,
3337
3431
  hasR2sql,
@@ -3387,6 +3481,7 @@ const runCodegen = (options) => {
3387
3481
  // `@lunora/bindings/kv` dep), so a visible KV tab always has a working
3388
3482
  // backend — never the reverse. The `ctx.kv` type-seam stays usage-only.
3389
3483
  hasKv: studioFeatures.kv,
3484
+ hasNotify,
3390
3485
  hasPayments,
3391
3486
  hasR2sql,
3392
3487
  hasQueue: queues.some((queue) => queue.mode === "push"),
@@ -1,7 +1,24 @@
1
- import { G as GENERATED_HEADER } from './emit-ClTbCLy4.mjs';
1
+ import { G as GENERATED_HEADER } from './emit-DIbr7U31.mjs';
2
2
  import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
3
3
  import { LUNORA_ERROR_CODES, objectSchema, argsObjectSchema, validatorIrToJsonSchema } from './LUNORA_ERROR_CODES-DvTLozCu.mjs';
4
4
 
5
+ const REST_PATH_PREFIX = "/_lunora/rest";
6
+ const splitFunctionPath = (functionPath) => {
7
+ const colon = functionPath.indexOf(":");
8
+ if (colon <= 0 || colon >= functionPath.length - 1 || functionPath.indexOf(":", colon + 1) !== -1) {
9
+ return void 0;
10
+ }
11
+ return { name: functionPath.slice(colon + 1), namespace: functionPath.slice(0, colon) };
12
+ };
13
+ const restPathForFunction = (functionPath) => {
14
+ const parts = splitFunctionPath(functionPath);
15
+ if (parts === void 0) {
16
+ return void 0;
17
+ }
18
+ return `${REST_PATH_PREFIX}/${parts.namespace}/${parts.name}`;
19
+ };
20
+ const restMethodForKind = (kind) => kind === "query" ? "GET" : "POST";
21
+
5
22
  const ERROR_COMPONENT_REF = "#/components/responses/LunoraError";
6
23
  const ROUTE_PARAM_RE = /:([A-Za-z_$][\w$]*)/gu;
7
24
  const pathParameterNames = (path) => [...path.matchAll(ROUTE_PARAM_RE)].map((match) => match[1]);
@@ -111,6 +128,55 @@ const rpcOperation = (definition) => {
111
128
  };
112
129
  return { operation, pathKey: `/_lunora/rpc#${functionPath}` };
113
130
  };
131
+ const restOperation = (definition) => {
132
+ const functionPath = `${sanitizeNamespace(definition.filePath)}:${definition.exportName}`;
133
+ const path = restPathForFunction(functionPath);
134
+ if (path === void 0) {
135
+ return void 0;
136
+ }
137
+ const tag = sanitizeNamespace(definition.filePath);
138
+ const method = restMethodForKind(definition.kind);
139
+ const isQuery = method === "GET";
140
+ const operation = {
141
+ description: `Public REST endpoint for the \`${definition.kind}\` \`${functionPath}\` (opt-in via \`.expose({ rest: true })\`). Routed through the procedure, so auth / RLS / validators are enforced.`,
142
+ operationId: `rest_${sanitizeNamespace(path)}`,
143
+ responses: {
144
+ "200": {
145
+ content: {
146
+ "application/json": {
147
+ schema: { description: "Procedure result. The shape is TS-inferred from the return type; best-effort — any JSON." }
148
+ }
149
+ },
150
+ description: "Successful result (TypeScript-inferred return shape, documented best-effort)."
151
+ },
152
+ default: { $ref: ERROR_COMPONENT_REF }
153
+ },
154
+ summary: `${method} ${path}`,
155
+ tags: [tag],
156
+ "x-lunora-function-kind": definition.kind
157
+ };
158
+ if (isQuery) {
159
+ const parameters = Object.entries(definition.args).map(([name, validator]) => {
160
+ const inner = validator.kind === "optional" ? validator.inner ?? validator : validator;
161
+ return {
162
+ description: `Argument \`${name}\` (JSON-encoded for non-string values).`,
163
+ in: "query",
164
+ name,
165
+ required: validator.kind !== "optional",
166
+ schema: validatorIrToJsonSchema(inner)
167
+ };
168
+ });
169
+ if (parameters.length > 0) {
170
+ operation.parameters = parameters;
171
+ }
172
+ return { method: "get", operation, path };
173
+ }
174
+ operation.requestBody = {
175
+ content: { "application/json": { schema: argsObjectSchema(definition.args) } },
176
+ required: Object.keys(definition.args).length > 0
177
+ };
178
+ return { method: "post", operation, path };
179
+ };
114
180
  const buildOpenApiDocument = (input) => {
115
181
  const version = input.version ?? "0.0.0";
116
182
  const paths = {};
@@ -128,6 +194,19 @@ const buildOpenApiDocument = (input) => {
128
194
  paths[pathKey] = { post: operation };
129
195
  tagNames.add(sanitizeNamespace(definition.filePath));
130
196
  }
197
+ for (const definition of rpcFunctions) {
198
+ if (definition.expose?.rest !== true) {
199
+ continue;
200
+ }
201
+ const rest = restOperation(definition);
202
+ if (rest === void 0) {
203
+ continue;
204
+ }
205
+ const pathItem = paths[rest.path] ?? {};
206
+ pathItem[rest.method] = rest.operation;
207
+ paths[rest.path] = pathItem;
208
+ tagNames.add(sanitizeNamespace(definition.filePath));
209
+ }
131
210
  const tags = [...tagNames].toSorted((a, b) => a.localeCompare(b)).map((name) => {
132
211
  return { description: `Operations declared in \`lunora/${name}\`.`, name };
133
212
  });
@@ -1,7 +1,7 @@
1
1
  import { relative, sep } from 'node:path';
2
2
  import { SyntaxKind, Node } from 'ts-morph';
3
3
  import { T as TS_EXTENSION_RE, e as enclosingExportName } from './discover-ast-CT6BgBr4.mjs';
4
- import { listLunoraSourceFiles } from './discoverFunctions-BJ-qR7Rg.mjs';
4
+ import { listLunoraSourceFiles } from './discoverFunctions-COG_Xkyz.mjs';
5
5
 
6
6
  const isAuthApiCall = (call) => {
7
7
  const callee = call.getExpression();
@@ -2,7 +2,7 @@ import { LunoraError } from '@lunora/errors';
2
2
  import { isValidCronExpression, compileCronSchedule, CRON_SCHEDULE_KINDS } from '@lunora/scheduler';
3
3
  import { SyntaxKind, Node } from 'ts-morph';
4
4
  import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
5
- import { listLunoraSourceFiles } from './discoverFunctions-BJ-qR7Rg.mjs';
5
+ import { listLunoraSourceFiles } from './discoverFunctions-COG_Xkyz.mjs';
6
6
  import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
7
7
 
8
8
  const CRON_METHODS = /* @__PURE__ */ new Set([...CRON_SCHEDULE_KINDS, "cron"]);
@@ -1,7 +1,7 @@
1
1
  import { readdirSync, lstatSync } from 'node:fs';
2
2
  import { join, extname, relative, sep } from 'node:path';
3
3
  import { Node, SyntaxKind } from 'ts-morph';
4
- import { a as parseObjectShape } from './parse-validator-BSJo1HGP.mjs';
4
+ import { a as parseObjectShape } from './parse-validator-BDGV8iue.mjs';
5
5
  import { s as sanitizeNamespace } from './paths-BRd6JHuF.mjs';
6
6
 
7
7
  const FUNCTION_KINDS = /* @__PURE__ */ new Set(["action", "mutation", "query", "stream"]);
@@ -70,6 +70,29 @@ const resolveBuilderRootKind = (receiver, followedLocal = false) => {
70
70
  }
71
71
  return INTERNAL_FACTORIES[rootName] ? "internal" : void 0;
72
72
  };
73
+ const exposeFromBuilderChain = (receiver) => {
74
+ let current = receiver;
75
+ while (Node.isCallExpression(current)) {
76
+ const inner = current.getExpression();
77
+ if (!Node.isPropertyAccessExpression(inner)) {
78
+ return void 0;
79
+ }
80
+ if (inner.getName() === "expose") {
81
+ const argument = current.getArguments()[0];
82
+ if (argument !== void 0 && Node.isObjectLiteralExpression(argument)) {
83
+ const restProperty = argument.getProperty("rest");
84
+ if (restProperty !== void 0 && Node.isPropertyAssignment(restProperty)) {
85
+ const initializer = restProperty.getInitializer();
86
+ const rest = initializer?.getText() === "true";
87
+ return { rest };
88
+ }
89
+ }
90
+ return {};
91
+ }
92
+ current = inner.getExpression();
93
+ }
94
+ return void 0;
95
+ };
73
96
  const argsFromCall = (call) => {
74
97
  const first = call.getArguments()[0];
75
98
  if (!first || !Node.isObjectLiteralExpression(first)) {
@@ -387,8 +410,10 @@ const discoverFromCall = (call) => {
387
410
  return void 0;
388
411
  }
389
412
  if (classified.receiver) {
413
+ const expose = exposeFromBuilderChain(classified.receiver);
390
414
  return {
391
415
  args: argsFromBuilderChain(classified.receiver),
416
+ ...expose ? { expose } : {},
392
417
  kind: classified.kind,
393
418
  returnType: returnTypeFromBuilderCall(call),
394
419
  visibility: classified.visibility
@@ -466,6 +491,7 @@ const functionIrFromCall = (call, exportName, relativePath) => {
466
491
  kind: discovered.kind,
467
492
  returnType: discovered.returnType,
468
493
  visibility: discovered.visibility,
494
+ ...discovered.expose ? { expose: discovered.expose } : {},
469
495
  ...discovered.lifecycle ? { lifecycle: discovered.lifecycle } : {}
470
496
  };
471
497
  };
@@ -1,7 +1,7 @@
1
1
  import { relative, sep } from 'node:path';
2
2
  import { Node } from 'ts-morph';
3
- import { listLunoraSourceFiles, unwrapHandlerReturn } from './discoverFunctions-BJ-qR7Rg.mjs';
4
- import { p as parseValidator, a as parseObjectShape } from './parse-validator-BSJo1HGP.mjs';
3
+ import { listLunoraSourceFiles, unwrapHandlerReturn } from './discoverFunctions-COG_Xkyz.mjs';
4
+ import { p as parseValidator, a as parseObjectShape } from './parse-validator-BDGV8iue.mjs';
5
5
 
6
6
  const TS_EXTENSION_RE = /\.ts$/u;
7
7
  const HTTP_VERBS = /* @__PURE__ */ new Set(["delete", "get", "head", "options", "patch", "post", "put"]);
@@ -1,6 +1,6 @@
1
1
  import { SyntaxKind, Node } from 'ts-morph';
2
2
  import { e as enclosingExportName } from './discover-ast-CT6BgBr4.mjs';
3
- import { listLunoraSourceFiles, lunoraRelativePath } from './discoverFunctions-BJ-qR7Rg.mjs';
3
+ import { listLunoraSourceFiles, lunoraRelativePath } from './discoverFunctions-COG_Xkyz.mjs';
4
4
 
5
5
  const isDatabaseInsertCall = (call) => {
6
6
  const callee = call.getExpression();
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJ-qR7Rg.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-COG_Xkyz.mjs';
3
3
 
4
4
  const isMaskCall = (node) => {
5
5
  if (!Node.isCallExpression(node)) {
@@ -1,7 +1,7 @@
1
1
  import { relative, sep } from 'node:path';
2
2
  import { SyntaxKind, Node } from 'ts-morph';
3
3
  import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
4
- import { listLunoraSourceFiles } from './discoverFunctions-BJ-qR7Rg.mjs';
4
+ import { listLunoraSourceFiles } from './discoverFunctions-COG_Xkyz.mjs';
5
5
 
6
6
  const TS_EXTENSION_RE = /\.ts$/u;
7
7
  const isDefineMigration = (identifier) => {
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJ-qR7Rg.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-COG_Xkyz.mjs';
3
3
 
4
4
  const PROPERTY_CALLS = {
5
5
  "crypto.getRandomValues": "crypto.getRandomValues",
@@ -1,5 +1,5 @@
1
1
  import { SyntaxKind, Node } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath } from './discoverFunctions-BJ-qR7Rg.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath } from './discoverFunctions-COG_Xkyz.mjs';
3
3
 
4
4
  const INDEX_METHODS = /* @__PURE__ */ new Set(["withIndex", "withSearchIndex"]);
5
5
  const isDatabaseQueryCall = (call) => {
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJ-qR7Rg.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-COG_Xkyz.mjs';
3
3
 
4
4
  const handlerOf = (call, receiver) => {
5
5
  if (receiver) {
@@ -1,5 +1,5 @@
1
1
  import { Node, SyntaxKind } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJ-qR7Rg.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-COG_Xkyz.mjs';
3
3
 
4
4
  const isRlsCall = (node) => {
5
5
  if (!Node.isCallExpression(node)) {
@@ -1,4 +1,4 @@
1
- import { listLunoraSourceFiles } from './discoverFunctions-BJ-qR7Rg.mjs';
1
+ import { listLunoraSourceFiles } from './discoverFunctions-COG_Xkyz.mjs';
2
2
 
3
3
  const SANDBOX_MODULE_SPECIFIERS = /* @__PURE__ */ new Set(["@lunora/agent", "@lunora/agent/sandbox"]);
4
4
  const scanImportDeclaration = (declaration) => {
@@ -1,7 +1,7 @@
1
1
  import { LunoraError } from '@lunora/errors';
2
2
  import { Node, SyntaxKind } from 'ts-morph';
3
3
  import { diagnosticAt } from './CodegenDiagnosticError-DyQ5FwkM.mjs';
4
- import { a as parseObjectShape } from './parse-validator-BSJo1HGP.mjs';
4
+ import { a as parseObjectShape } from './parse-validator-BDGV8iue.mjs';
5
5
  import { createRequire } from 'node:module';
6
6
  import { join } from 'node:path';
7
7
 
@@ -109,6 +109,7 @@ const runtimeTableToIR = (builder, bareName) => {
109
109
  warnDroppedTableFeatures(builder, bareName);
110
110
  return {
111
111
  ...builder.isExternallyManaged ? { externallyManaged: true } : {},
112
+ geoIndexes: [],
112
113
  indexes,
113
114
  name: bareName,
114
115
  rankIndexes: [],
@@ -334,6 +335,25 @@ const parseSearchIndexCall = (args) => {
334
335
  }
335
336
  return { field, filterFields, name: indexNameOf(indexName) };
336
337
  };
338
+ const parseGeoIndexCall = (args) => {
339
+ const [indexName, optionsExpression] = args;
340
+ let field = "_unknown_";
341
+ let precision;
342
+ if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
343
+ field = getStringProperty(optionsExpression, "field") ?? field;
344
+ precision = getNumberProperty(optionsExpression, "precision");
345
+ }
346
+ return { field, name: indexNameOf(indexName), precision };
347
+ };
348
+ const parseTtlCall = (args) => {
349
+ const [fieldArgument, optionsExpression] = args;
350
+ const field = fieldArgument && Node.isStringLiteral(fieldArgument) ? fieldArgument.getLiteralText() : "_unknown_";
351
+ let after;
352
+ if (optionsExpression && Node.isObjectLiteralExpression(optionsExpression)) {
353
+ after = getNumberProperty(optionsExpression, "after");
354
+ }
355
+ return { after, field };
356
+ };
337
357
  const rankSortKeyFromElement = (element) => {
338
358
  if (!Node.isObjectLiteralExpression(element)) {
339
359
  return void 0;
@@ -441,6 +461,10 @@ const applyTableMethod = (accumulator, method, args, name) => {
441
461
  accumulator.externallyManaged = true;
442
462
  break;
443
463
  }
464
+ case "geoIndex": {
465
+ accumulator.geoIndexes.push(parseGeoIndexCall(args));
466
+ break;
467
+ }
444
468
  case "global": {
445
469
  accumulator.shardMode = "global";
446
470
  accumulator.globalBackend = parseGlobalBackend(args);
@@ -483,6 +507,10 @@ const applyTableMethod = (accumulator, method, args, name) => {
483
507
  accumulator.externallyManaged = true;
484
508
  break;
485
509
  }
510
+ case "ttl": {
511
+ accumulator.ttl = parseTtlCall(args);
512
+ break;
513
+ }
486
514
  case "vectorize": {
487
515
  const vectorIndex = parseVectorizeCall(args, name);
488
516
  if (vectorIndex) {
@@ -495,6 +523,7 @@ const applyTableMethod = (accumulator, method, args, name) => {
495
523
  const parseTableBuilder = (expression, name) => {
496
524
  const accumulator = {
497
525
  externallyManaged: false,
526
+ geoIndexes: [],
498
527
  indexes: [],
499
528
  isPublic: false,
500
529
  rankIndexes: [],
@@ -527,6 +556,7 @@ const parseTableBuilder = (expression, name) => {
527
556
  return {
528
557
  externallyManaged: accumulator.externallyManaged,
529
558
  externalSource: accumulator.externalSource,
559
+ geoIndexes: accumulator.geoIndexes,
530
560
  globalBackend: accumulator.shardMode === "global" ? accumulator.globalBackend ?? "d1" : void 0,
531
561
  indexes: accumulator.indexes,
532
562
  isPublic: accumulator.isPublic,
@@ -537,6 +567,7 @@ const parseTableBuilder = (expression, name) => {
537
567
  shape,
538
568
  shardMode: accumulator.shardMode,
539
569
  softDelete: accumulator.softDelete,
570
+ ttl: accumulator.ttl,
540
571
  vectorIndexes: accumulator.vectorIndexes
541
572
  };
542
573
  };
@@ -1,5 +1,5 @@
1
1
  import { Node } from 'ts-morph';
2
- import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-BJ-qR7Rg.mjs';
2
+ import { listLunoraSourceFiles, lunoraRelativePath, classifyProcedureCall } from './discoverFunctions-COG_Xkyz.mjs';
3
3
 
4
4
  const STORAGE_OPERATIONS = /* @__PURE__ */ new Set(["delete", "list", "read", "write"]);
5
5
  const isStorageRulesCall = (node) => {