@rebasepro/server 0.13.0 → 0.13.1-canary.g06dbe5b

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 (125) hide show
  1. package/dist/{admin_block-CcSGdH7M.js → admin_block-H86dCPsj.js} +62 -2
  2. package/dist/admin_block-H86dCPsj.js.map +1 -0
  3. package/dist/api/ast-schema-editor.d.ts +74 -6
  4. package/dist/api/errors.d.ts +0 -6
  5. package/dist/api/openapi-generator.d.ts +14 -0
  6. package/dist/api/rest/api-generator.d.ts +1 -1
  7. package/dist/api/rest/idempotency.d.ts +62 -4
  8. package/dist/api/rest/query-parser.d.ts +15 -1
  9. package/dist/api/rest/write-validation.d.ts +52 -9
  10. package/dist/auth/adapter-middleware.d.ts +3 -1
  11. package/dist/auth/apple-oauth.d.ts +16 -11
  12. package/dist/auth/bitbucket-oauth.d.ts +2 -4
  13. package/dist/auth/builtin-auth-adapter.d.ts +2 -0
  14. package/dist/auth/discord-oauth.d.ts +5 -6
  15. package/dist/auth/facebook-oauth.d.ts +2 -4
  16. package/dist/auth/github-oauth.d.ts +2 -4
  17. package/dist/auth/gitlab-oauth.d.ts +6 -4
  18. package/dist/auth/google-oauth.d.ts +1 -0
  19. package/dist/auth/index.d.ts +8 -1
  20. package/dist/auth/interfaces.d.ts +68 -1
  21. package/dist/auth/jwt.d.ts +40 -0
  22. package/dist/auth/linkedin-oauth.d.ts +2 -4
  23. package/dist/auth/mfa-gate.d.ts +42 -0
  24. package/dist/auth/mfa-routes.d.ts +26 -1
  25. package/dist/auth/mfa.d.ts +16 -0
  26. package/dist/auth/microsoft-oauth.d.ts +19 -4
  27. package/dist/auth/oauth-code-flow.d.ts +66 -0
  28. package/dist/auth/oauth-signin-policy.d.ts +61 -0
  29. package/dist/auth/oidc-id-token.d.ts +61 -0
  30. package/dist/auth/rate-limiter.d.ts +37 -2
  31. package/dist/auth/rls-scope.d.ts +25 -0
  32. package/dist/auth/routes.d.ts +8 -0
  33. package/dist/auth/slack-oauth.d.ts +2 -4
  34. package/dist/auth/spotify-oauth.d.ts +2 -4
  35. package/dist/auth/twitter-oauth.d.ts +2 -5
  36. package/dist/{auth-CuC9M2x6.js → auth-DkAHqvf5.js} +1604 -391
  37. package/dist/auth-DkAHqvf5.js.map +1 -0
  38. package/dist/{backup-CVggVhR2.js → backup-DLluVyuA.js} +2 -2
  39. package/dist/{backup-CVggVhR2.js.map → backup-DLluVyuA.js.map} +1 -1
  40. package/dist/boot/boot.d.ts +19 -0
  41. package/dist/boot/ddl-bootstrap.d.ts +70 -0
  42. package/dist/{contract-routes-Dj8i5AiM.js → contract-routes-BB1U05sS.js} +3 -3
  43. package/dist/{contract-routes-Dj8i5AiM.js.map → contract-routes-BB1U05sS.js.map} +1 -1
  44. package/dist/cron/cron-scheduler.d.ts +8 -3
  45. package/dist/cron/define-cron.d.ts +17 -3
  46. package/dist/{cron-loader-B1S2MCSl.js → cron-loader-3U5aGILy.js} +2 -2
  47. package/dist/{cron-loader-B1S2MCSl.js.map → cron-loader-3U5aGILy.js.map} +1 -1
  48. package/dist/{cron-routes-CrQ0tK-_.js → cron-routes-rZgwlOz4.js} +2 -2
  49. package/dist/{cron-routes-CrQ0tK-_.js.map → cron-routes-rZgwlOz4.js.map} +1 -1
  50. package/dist/{cron-scheduler-B3RFt0HS.js → cron-scheduler-FJAaCAXm.js} +30 -5
  51. package/dist/cron-scheduler-FJAaCAXm.js.map +1 -0
  52. package/dist/{cron-store-BywZsyfZ.js → cron-store-9NmUDfzL.js} +66 -47
  53. package/dist/cron-store-9NmUDfzL.js.map +1 -0
  54. package/dist/ddl-bootstrap-BhXbTnBl.js +183 -0
  55. package/dist/ddl-bootstrap-BhXbTnBl.js.map +1 -0
  56. package/dist/email/html.d.ts +54 -0
  57. package/dist/email/index.d.ts +3 -0
  58. package/dist/email/link-base.d.ts +39 -0
  59. package/dist/email/smtp-email-service.d.ts +7 -1
  60. package/dist/email/templates.d.ts +9 -1
  61. package/dist/email/types.d.ts +11 -1
  62. package/dist/{errors-CgkCzoj7.js → errors-B1WZEdsK.js} +3 -11
  63. package/dist/errors-B1WZEdsK.js.map +1 -0
  64. package/dist/function-loader-D1SwtCa5.js +139 -0
  65. package/dist/function-loader-D1SwtCa5.js.map +1 -0
  66. package/dist/{function-routes-C0cLIy3N.js → function-routes-Btcez1T-.js} +18 -6
  67. package/dist/function-routes-Btcez1T-.js.map +1 -0
  68. package/dist/functions/define-function.d.ts +25 -6
  69. package/dist/functions/function-loader.d.ts +23 -0
  70. package/dist/functions/function-routes.d.ts +7 -1
  71. package/dist/functions/request-timeout.d.ts +34 -0
  72. package/dist/history/history-routes.d.ts +6 -0
  73. package/dist/index.d.ts +2 -1
  74. package/dist/index.es.js +1960 -794
  75. package/dist/index.es.js.map +1 -1
  76. package/dist/init/docs.d.ts +10 -1
  77. package/dist/init/process-safety.d.ts +25 -0
  78. package/dist/init.d.ts +27 -0
  79. package/dist/{jwt-DD6EtpGj.js → jwt-Cuq6MwNy.js} +70 -8
  80. package/dist/jwt-Cuq6MwNy.js.map +1 -0
  81. package/dist/logger-DfvF_8r-.js +190 -0
  82. package/dist/logger-DfvF_8r-.js.map +1 -0
  83. package/dist/openapi-generator-BQxxxDpb.js +865 -0
  84. package/dist/openapi-generator-BQxxxDpb.js.map +1 -0
  85. package/dist/request-timeout-RivJsME0.js +65 -0
  86. package/dist/request-timeout-RivJsME0.js.map +1 -0
  87. package/dist/schema-editor-routes-DZFKGXgq.js +437 -0
  88. package/dist/schema-editor-routes-DZFKGXgq.js.map +1 -0
  89. package/dist/serve-spa.d.ts +5 -4
  90. package/dist/services/outbound-url-guard.d.ts +53 -0
  91. package/dist/services/routed-realtime-service.d.ts +10 -2
  92. package/dist/services/webhook-service.d.ts +76 -1
  93. package/dist/singleton.d.ts +25 -8
  94. package/dist/{src-Cum9kox5.js → src-By48Ffg0.js} +322 -70
  95. package/dist/src-By48Ffg0.js.map +1 -0
  96. package/dist/{src-_qQ3RNCK.js → src-Ca6NhxKs.js} +79 -2
  97. package/dist/src-Ca6NhxKs.js.map +1 -0
  98. package/dist/storage/LocalStorageController.d.ts +12 -1
  99. package/dist/storage/image-transform.d.ts +57 -0
  100. package/dist/storage/keys.d.ts +98 -0
  101. package/dist/storage/routes.d.ts +11 -0
  102. package/dist/storage/tus-handler.d.ts +7 -1
  103. package/dist/utils/logger.d.ts +18 -0
  104. package/dist/utils/logging.d.ts +0 -4
  105. package/dist/utils/sql.d.ts +11 -6
  106. package/package.json +7 -6
  107. package/dist/admin_block-CcSGdH7M.js.map +0 -1
  108. package/dist/auth-CuC9M2x6.js.map +0 -1
  109. package/dist/backend-CIxN4FVm.js +0 -15
  110. package/dist/backend-CIxN4FVm.js.map +0 -1
  111. package/dist/cron-scheduler-B3RFt0HS.js.map +0 -1
  112. package/dist/cron-store-BywZsyfZ.js.map +0 -1
  113. package/dist/errors-CgkCzoj7.js.map +0 -1
  114. package/dist/function-loader-B_1fYfUY.js +0 -86
  115. package/dist/function-loader-B_1fYfUY.js.map +0 -1
  116. package/dist/function-routes-C0cLIy3N.js.map +0 -1
  117. package/dist/jwt-DD6EtpGj.js.map +0 -1
  118. package/dist/logger-BYU66ENZ.js +0 -94
  119. package/dist/logger-BYU66ENZ.js.map +0 -1
  120. package/dist/openapi-generator-BEwyiaAr.js +0 -597
  121. package/dist/openapi-generator-BEwyiaAr.js.map +0 -1
  122. package/dist/schema-editor-routes-CbF20Mf1.js +0 -248
  123. package/dist/schema-editor-routes-CbF20Mf1.js.map +0 -1
  124. package/dist/src-Cum9kox5.js.map +0 -1
  125. package/dist/src-_qQ3RNCK.js.map +0 -1
@@ -1,94 +0,0 @@
1
- import { createRequire as __createRequire } from "module";
2
- import process from "process";
3
- __createRequire(import.meta.url);
4
- //#region src/utils/logger.ts
5
- /** Google Cloud Logging severity strings. */
6
- var GCP_SEVERITY = {
7
- debug: "DEBUG",
8
- info: "INFO",
9
- warn: "WARNING",
10
- error: "ERROR"
11
- };
12
- var LOG_PRIORITY = {
13
- debug: 0,
14
- info: 1,
15
- warn: 2,
16
- error: 3
17
- };
18
- function isProduction() {
19
- return process.env.NODE_ENV === "production";
20
- }
21
- function getMinLevel() {
22
- const env = (process.env.LOG_LEVEL || "info").toLowerCase();
23
- if (env in LOG_PRIORITY) return env;
24
- return "info";
25
- }
26
- /**
27
- * Serialise an Error into a plain object (stack + message).
28
- * Handles non-Error values gracefully.
29
- */
30
- function serialiseError(value) {
31
- if (value instanceof Error) return {
32
- name: value.name,
33
- message: value.message,
34
- stack: value.stack
35
- };
36
- return { value: String(value) };
37
- }
38
- function formatData(data) {
39
- if (!data) return void 0;
40
- const out = {};
41
- for (const [key, val] of Object.entries(data)) if (val instanceof Error) out[key] = serialiseError(val);
42
- else out[key] = val;
43
- return out;
44
- }
45
- function createLogger(defaultFields = {}) {
46
- const minLevel = getMinLevel();
47
- function emit(level, message, data) {
48
- if (LOG_PRIORITY[level] < LOG_PRIORITY[minLevel]) return;
49
- const merged = {
50
- ...defaultFields,
51
- ...formatData(data)
52
- };
53
- if (isProduction()) {
54
- const entry = {
55
- severity: GCP_SEVERITY[level],
56
- message,
57
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
58
- ...merged
59
- };
60
- const line = JSON.stringify(entry);
61
- if (level === "error") process.stderr.write(line + "\n");
62
- else process.stdout.write(line + "\n");
63
- } else {
64
- const prefix = level === "error" ? "❌" : level === "warn" ? "⚠️" : level === "info" ? "ℹ️" : "🐛";
65
- const extra = Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : "";
66
- const out = `${prefix} [${level.toUpperCase()}] ${message}${extra}`;
67
- if (level === "error") console.error(out);
68
- else if (level === "warn") console.warn(out);
69
- else console.log(out);
70
- }
71
- }
72
- return {
73
- debug: (msg, data) => emit("debug", msg, data),
74
- info: (msg, data) => emit("info", msg, data),
75
- warn: (msg, data) => emit("warn", msg, data),
76
- error: (msg, data) => emit("error", msg, data),
77
- child(fields) {
78
- return createLogger({
79
- ...defaultFields,
80
- ...fields
81
- });
82
- }
83
- };
84
- }
85
- /**
86
- * Singleton logger instance.
87
- * In production: emits JSON lines with `severity`, `message`, `timestamp`.
88
- * In development: emits human-readable prefixed lines.
89
- */
90
- var logger = createLogger();
91
- //#endregion
92
- export { logger as t };
93
-
94
- //# sourceMappingURL=logger-BYU66ENZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger-BYU66ENZ.js","names":[],"sources":["../src/utils/logger.ts"],"sourcesContent":["/**\n * Structured Logger for Rebase Backend\n *\n * Outputs JSON lines when `NODE_ENV=production`, human-readable prefixed\n * lines otherwise. Designed to work with Google Cloud Logging severity levels.\n *\n * Usage:\n * import { logger } from \"./utils/logger\";\n * logger.info(\"Server started\", { port: 3001 });\n * logger.error(\"Request failed\", { path: \"/api/test\", error: err });\n */\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\n/** Google Cloud Logging severity strings. */\nconst GCP_SEVERITY: Record<LogLevel, string> = {\n debug: \"DEBUG\",\n info: \"INFO\",\n warn: \"WARNING\",\n error: \"ERROR\"\n};\n\nconst LOG_PRIORITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3\n};\n\nexport interface LogEntry {\n severity: string;\n message: string;\n timestamp: string;\n [key: string]: unknown;\n}\n\nexport interface Logger {\n debug(message: string, data?: Record<string, unknown>): void;\n info(message: string, data?: Record<string, unknown>): void;\n warn(message: string, data?: Record<string, unknown>): void;\n error(message: string, data?: Record<string, unknown>): void;\n child(defaultFields: Record<string, unknown>): Logger;\n}\n\nfunction isProduction(): boolean {\n return process.env.NODE_ENV === \"production\";\n}\n\nfunction getMinLevel(): LogLevel {\n const env = (process.env.LOG_LEVEL || \"info\").toLowerCase();\n if (env in LOG_PRIORITY) return env as LogLevel;\n return \"info\";\n}\n\n/**\n * Serialise an Error into a plain object (stack + message).\n * Handles non-Error values gracefully.\n */\nfunction serialiseError(value: unknown): Record<string, unknown> {\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: value.stack\n };\n }\n return { value: String(value) };\n}\n\nfunction formatData(data?: Record<string, unknown>): Record<string, unknown> | undefined {\n if (!data) return undefined;\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(data)) {\n if (val instanceof Error) {\n out[key] = serialiseError(val);\n } else {\n out[key] = val;\n }\n }\n return out;\n}\n\nfunction createLogger(defaultFields: Record<string, unknown> = {}): Logger {\n const minLevel = getMinLevel();\n\n function emit(level: LogLevel, message: string, data?: Record<string, unknown>): void {\n if (LOG_PRIORITY[level] < LOG_PRIORITY[minLevel]) return;\n\n const merged = { ...defaultFields,\n...formatData(data) };\n\n if (isProduction()) {\n // Structured JSON for Cloud Logging\n const entry: LogEntry = {\n severity: GCP_SEVERITY[level],\n message,\n timestamp: new Date().toISOString(),\n ...merged\n };\n const line = JSON.stringify(entry);\n\n if (level === \"error\") {\n process.stderr.write(line + \"\\n\");\n } else {\n process.stdout.write(line + \"\\n\");\n }\n } else {\n // Human-readable for development\n const prefix = level === \"error\" ? \"❌\"\n : level === \"warn\" ? \"⚠️\"\n : level === \"info\" ? \"ℹ️\"\n : \"🐛\";\n const extra = Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : \"\";\n const out = `${prefix} [${level.toUpperCase()}] ${message}${extra}`;\n\n if (level === \"error\") {\n console.error(out);\n } else if (level === \"warn\") {\n console.warn(out);\n } else {\n console.log(out);\n }\n }\n }\n\n return {\n debug: (msg, data) => emit(\"debug\", msg, data),\n info: (msg, data) => emit(\"info\", msg, data),\n warn: (msg, data) => emit(\"warn\", msg, data),\n error: (msg, data) => emit(\"error\", msg, data),\n child(fields: Record<string, unknown>): Logger {\n return createLogger({ ...defaultFields,\n...fields });\n }\n };\n}\n\n/**\n * Singleton logger instance.\n * In production: emits JSON lines with `severity`, `message`, `timestamp`.\n * In development: emits human-readable prefixed lines.\n */\nexport const logger: Logger = createLogger();\n"],"mappings":";;;;;AAeA,IAAM,eAAyC;CAC3C,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;AACX;AAEA,IAAM,eAAyC;CAC3C,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;AACX;AAiBA,SAAS,eAAwB;CAC7B,OAAA,QAAA,IAAA,aAAgC;AACpC;AAEA,SAAS,cAAwB;CAC7B,MAAM,OAAO,QAAQ,IAAI,aAAa,OAAA,CAAQ,YAAY;CAC1D,IAAI,OAAO,cAAc,OAAO;CAChC,OAAO;AACX;;;;;AAMA,SAAS,eAAe,OAAyC;CAC7D,IAAI,iBAAiB,OACjB,OAAO;EACH,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,OAAO,MAAM;CACjB;CAEJ,OAAO,EAAE,OAAO,OAAO,KAAK,EAAE;AAClC;AAEA,SAAS,WAAW,MAAqE;CACrF,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,IAAI,GACxC,IAAI,eAAe,OACf,IAAI,OAAO,eAAe,GAAG;MAE7B,IAAI,OAAO;CAGnB,OAAO;AACX;AAEA,SAAS,aAAa,gBAAyC,CAAC,GAAW;CACvE,MAAM,WAAW,YAAY;CAE7B,SAAS,KAAK,OAAiB,SAAiB,MAAsC;EAClF,IAAI,aAAa,SAAS,aAAa,WAAW;EAElD,MAAM,SAAS;GAAE,GAAG;GAC5B,GAAG,WAAW,IAAI;EAAE;EAEZ,IAAI,aAAa,GAAG;GAEhB,MAAM,QAAkB;IACpB,UAAU,aAAa;IACvB;IACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;IAClC,GAAG;GACP;GACA,MAAM,OAAO,KAAK,UAAU,KAAK;GAEjC,IAAI,UAAU,SACV,QAAQ,OAAO,MAAM,OAAO,IAAI;QAEhC,QAAQ,OAAO,MAAM,OAAO,IAAI;EAExC,OAAO;GAEH,MAAM,SAAS,UAAU,UAAU,MAC7B,UAAU,SAAS,OACnB,UAAU,SAAS,OACnB;GACN,MAAM,QAAQ,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,IAAI,IAAI,KAAK,UAAU,MAAM,MAAM;GAC9E,MAAM,MAAM,GAAG,OAAO,IAAI,MAAM,YAAY,EAAE,IAAI,UAAU;GAE5D,IAAI,UAAU,SACV,QAAQ,MAAM,GAAG;QACd,IAAI,UAAU,QACjB,QAAQ,KAAK,GAAG;QAEhB,QAAQ,IAAI,GAAG;EAEvB;CACJ;CAEA,OAAO;EACH,QAAQ,KAAK,SAAS,KAAK,SAAS,KAAK,IAAI;EAC7C,OAAO,KAAK,SAAS,KAAK,QAAQ,KAAK,IAAI;EAC3C,OAAO,KAAK,SAAS,KAAK,QAAQ,KAAK,IAAI;EAC3C,QAAQ,KAAK,SAAS,KAAK,SAAS,KAAK,IAAI;EAC7C,MAAM,QAAyC;GAC3C,OAAO,aAAa;IAAE,GAAG;IACrC,GAAG;GAAO,CAAC;EACH;CACJ;AACJ;;;;;;AAOA,IAAa,SAAiB,aAAa"}
@@ -1,597 +0,0 @@
1
- import { createRequire as __createRequire } from "module";
2
- import "process";
3
- __createRequire(import.meta.url);
4
- import { m as resolveCollectionRelations } from "./src-Cum9kox5.js";
5
- import "./src-_qQ3RNCK.js";
6
- //#region ../types/src/types/relations.ts
7
- /** @group Models */
8
- function isToMany(relation) {
9
- return relation.cardinality === "many";
10
- }
11
- //#endregion
12
- //#region src/api/openapi-generator.ts
13
- function generateOpenApiSpec(collections, options = {}) {
14
- const basePath = options.basePath ?? "/api";
15
- const requireAuth = options.requireAuth ?? true;
16
- const spec = {
17
- openapi: "3.0.3",
18
- info: {
19
- title: "Rebase API",
20
- version: "1.0.0",
21
- description: "Auto-generated REST API from Rebase collection definitions. This is the same API consumed by the `@rebasepro/client` SDK."
22
- },
23
- servers: [{
24
- url: basePath,
25
- description: "API Server"
26
- }],
27
- paths: {},
28
- components: {
29
- schemas: {
30
- ErrorResponse: {
31
- type: "object",
32
- properties: { error: {
33
- type: "object",
34
- required: ["message", "code"],
35
- properties: {
36
- message: { type: "string" },
37
- code: { type: "string" },
38
- details: {}
39
- }
40
- } }
41
- },
42
- PaginationMeta: {
43
- type: "object",
44
- properties: {
45
- total: {
46
- type: "integer",
47
- description: "Total number of matching records"
48
- },
49
- limit: {
50
- type: "integer",
51
- description: "Page size used for this query"
52
- },
53
- offset: {
54
- type: "integer",
55
- description: "Number of records skipped"
56
- },
57
- hasMore: {
58
- type: "boolean",
59
- description: "Whether more records exist beyond this page"
60
- }
61
- }
62
- }
63
- },
64
- securitySchemes: {}
65
- },
66
- tags: []
67
- };
68
- if (requireAuth) {
69
- spec.components.securitySchemes = {
70
- bearerAuth: {
71
- type: "http",
72
- scheme: "bearer",
73
- bearerFormat: "JWT",
74
- description: "JWT access token obtained from `POST /auth/login` or `POST /auth/register`. Can also be a static service key for server-to-server authentication."
75
- },
76
- queryToken: {
77
- type: "apiKey",
78
- in: "query",
79
- name: "token",
80
- description: "Alternative: pass the JWT or service key as a `token` query parameter."
81
- }
82
- };
83
- spec.security = [{ bearerAuth: [] }, { queryToken: [] }];
84
- }
85
- const paths = spec.paths;
86
- const schemas = spec.components.schemas;
87
- const tags = spec.tags;
88
- for (const collection of collections || []) {
89
- const schemaName = toPascalCase(collection.singularName || collection.name);
90
- const slug = collection.slug;
91
- tags.push({
92
- name: collection.name,
93
- description: collection.description || `CRUD operations for ${collection.name}`
94
- });
95
- schemas[schemaName] = buildCollectionSchema(collection);
96
- schemas[`${schemaName}Input`] = buildCollectionInputSchema(collection);
97
- const dataPath = `/data/${slug}`;
98
- paths[dataPath] = {
99
- get: {
100
- tags: [collection.name],
101
- summary: `List ${collection.name}`,
102
- operationId: `list${schemaName}`,
103
- parameters: [
104
- {
105
- name: "limit",
106
- in: "query",
107
- schema: {
108
- type: "integer",
109
- default: 20,
110
- maximum: 100
111
- },
112
- description: "Maximum number of records to return"
113
- },
114
- {
115
- name: "offset",
116
- in: "query",
117
- schema: {
118
- type: "integer",
119
- default: 0
120
- },
121
- description: "Number of records to skip"
122
- },
123
- {
124
- name: "page",
125
- in: "query",
126
- schema: {
127
- type: "integer",
128
- minimum: 1
129
- },
130
- description: "Page number (alternative to offset). Calculates offset as (page-1)*limit"
131
- },
132
- {
133
- name: "orderBy",
134
- in: "query",
135
- schema: { type: "string" },
136
- description: "Sort field and direction. Accepts `field:asc` or `field:desc`, or a JSON array `[{\"field\":\"name\",\"direction\":\"asc\"}]`",
137
- example: "created_at:desc"
138
- },
139
- {
140
- name: "where",
141
- in: "query",
142
- schema: { type: "string" },
143
- description: "JSON object filter, mapping each field to a `[operator, value]` tuple. Combines with the per-field `?field=op.value` parameters below; on the same field, the per-field parameter wins.",
144
- example: "{\"status\":[\"==\",\"active\"]}"
145
- },
146
- {
147
- name: "include",
148
- in: "query",
149
- schema: { type: "string" },
150
- description: "Comma-separated list of relations to include (eager-load). Use `*` for all relations.",
151
- example: "author,tags"
152
- },
153
- {
154
- name: "fields",
155
- in: "query",
156
- schema: { type: "string" },
157
- description: "Comma-separated list of fields to return (field selection)",
158
- example: "id,name,created_at"
159
- },
160
- {
161
- name: "searchString",
162
- in: "query",
163
- schema: { type: "string" },
164
- description: "Full-text search query"
165
- },
166
- ...buildFilterParameters(collection)
167
- ],
168
- responses: {
169
- 200: {
170
- description: "Paginated list of entities",
171
- content: { "application/json": { schema: {
172
- type: "object",
173
- properties: {
174
- data: {
175
- type: "array",
176
- items: { $ref: `#/components/schemas/${schemaName}` }
177
- },
178
- meta: { $ref: "#/components/schemas/PaginationMeta" }
179
- }
180
- } } }
181
- },
182
- ...errorResponses(requireAuth)
183
- }
184
- },
185
- post: {
186
- tags: [collection.name],
187
- summary: `Create ${collection.singularName || collection.name}`,
188
- operationId: `create${schemaName}`,
189
- requestBody: {
190
- required: true,
191
- content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}Input` } } }
192
- },
193
- responses: {
194
- 201: {
195
- description: "Created entity",
196
- content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
197
- },
198
- ...errorResponses(requireAuth)
199
- }
200
- }
201
- };
202
- const entityPath = `/data/${slug}/{id}`;
203
- paths[entityPath] = {
204
- get: {
205
- tags: [collection.name],
206
- summary: `Get ${collection.singularName || collection.name} by ID`,
207
- operationId: `get${schemaName}ById`,
208
- parameters: [{
209
- name: "id",
210
- in: "path",
211
- required: true,
212
- schema: { type: "string" },
213
- description: "Entity ID"
214
- }, {
215
- name: "include",
216
- in: "query",
217
- schema: { type: "string" },
218
- description: "Comma-separated list of relations to include",
219
- example: "author,tags"
220
- }],
221
- responses: {
222
- 200: {
223
- description: "Entity found",
224
- content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
225
- },
226
- 404: {
227
- description: "Entity not found",
228
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
229
- },
230
- ...errorResponses(requireAuth)
231
- }
232
- },
233
- put: {
234
- tags: [collection.name],
235
- summary: `Update ${collection.singularName || collection.name}`,
236
- operationId: `update${schemaName}`,
237
- parameters: [{
238
- name: "id",
239
- in: "path",
240
- required: true,
241
- schema: { type: "string" },
242
- description: "Entity ID"
243
- }],
244
- requestBody: {
245
- required: true,
246
- content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}Input` } } }
247
- },
248
- responses: {
249
- 200: {
250
- description: "Updated entity",
251
- content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
252
- },
253
- 404: {
254
- description: "Entity not found",
255
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
256
- },
257
- ...errorResponses(requireAuth)
258
- }
259
- },
260
- delete: {
261
- tags: [collection.name],
262
- summary: `Delete ${collection.singularName || collection.name}`,
263
- operationId: `delete${schemaName}`,
264
- parameters: [{
265
- name: "id",
266
- in: "path",
267
- required: true,
268
- schema: { type: "string" },
269
- description: "Entity ID"
270
- }],
271
- responses: {
272
- 204: { description: "Deleted successfully" },
273
- 404: {
274
- description: "Entity not found",
275
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
276
- },
277
- ...errorResponses(requireAuth)
278
- }
279
- }
280
- };
281
- }
282
- for (const collection of collections || []) {
283
- const slug = collection.slug;
284
- const schemaName = toPascalCase(collection.singularName || collection.name);
285
- const relations = Object.values(resolveCollectionRelations(collection)).filter(isToMany);
286
- for (const relation of relations) {
287
- const relationName = relation.relationName;
288
- const targetCollection = relation.target();
289
- const targetSchema = toPascalCase(targetCollection.singularName || targetCollection.name);
290
- const subPath = `/data/${slug}/{parentId}/${relationName}`;
291
- paths[subPath] = { get: {
292
- tags: [collection.name],
293
- summary: `List ${relationName} for ${withIndefiniteArticle(collection.singularName || collection.name)}`,
294
- operationId: `list${schemaName}${toPascalCase(relationName)}`,
295
- parameters: [
296
- {
297
- name: "parentId",
298
- in: "path",
299
- required: true,
300
- schema: { type: "string" },
301
- description: `${collection.singularName || collection.name} ID`
302
- },
303
- {
304
- name: "limit",
305
- in: "query",
306
- schema: {
307
- type: "integer",
308
- default: 20
309
- }
310
- },
311
- {
312
- name: "offset",
313
- in: "query",
314
- schema: {
315
- type: "integer",
316
- default: 0
317
- }
318
- },
319
- {
320
- name: "orderBy",
321
- in: "query",
322
- schema: { type: "string" }
323
- },
324
- {
325
- name: "searchString",
326
- in: "query",
327
- schema: { type: "string" }
328
- }
329
- ],
330
- responses: {
331
- 200: {
332
- description: `List of related ${relationName}`,
333
- content: { "application/json": { schema: {
334
- type: "object",
335
- properties: {
336
- data: {
337
- type: "array",
338
- items: schemas[targetSchema] ? { $ref: `#/components/schemas/${targetSchema}` } : { type: "object" }
339
- },
340
- meta: { $ref: "#/components/schemas/PaginationMeta" }
341
- }
342
- } } }
343
- },
344
- ...errorResponses(requireAuth)
345
- }
346
- } };
347
- }
348
- }
349
- return spec;
350
- }
351
- /**
352
- * Build the component schema for a collection (output / read shape).
353
- * All fields are included (including relation foreign keys).
354
- */
355
- function buildCollectionSchema(collection) {
356
- const properties = { id: {
357
- type: "string",
358
- description: "Unique identifier"
359
- } };
360
- const required = ["id"];
361
- for (const [key, property] of Object.entries(collection.properties)) {
362
- if (property.type === "relation") continue;
363
- properties[key] = convertPropertyToSchema(property);
364
- if (property.validation?.required) required.push(key);
365
- }
366
- return {
367
- type: "object",
368
- required: required.length > 0 ? required : void 0,
369
- properties
370
- };
371
- }
372
- /**
373
- * Build an input schema (for POST/PUT) — excludes auto-generated fields.
374
- */
375
- function buildCollectionInputSchema(collection) {
376
- const properties = {};
377
- const required = [];
378
- for (const [key, property] of Object.entries(collection.properties)) {
379
- if (property.type === "relation") continue;
380
- if (property.type === "date" && property.autoValue) continue;
381
- if ("isId" in property && property.isId && property.isId !== "manual" && property.isId !== true) continue;
382
- properties[key] = convertPropertyToSchema(property);
383
- if (property.validation?.required) required.push(key);
384
- }
385
- properties["id"] = {
386
- type: "string",
387
- description: "Optional: client-assigned ID. If omitted, the server generates one."
388
- };
389
- return {
390
- type: "object",
391
- required: required.length > 0 ? required : void 0,
392
- properties
393
- };
394
- }
395
- /**
396
- * Convert a Rebase Property to an OpenAPI 3.0 schema object.
397
- */
398
- function convertPropertyToSchema(property) {
399
- const base = {};
400
- if (property.name) base.description = property.name;
401
- switch (property.type) {
402
- case "string": {
403
- const sp = property;
404
- base.type = "string";
405
- if (sp.enum) {
406
- const enumValues = resolveEnumValues(sp.enum);
407
- if (enumValues.length > 0) base.enum = enumValues;
408
- }
409
- if (sp.validation) {
410
- if (sp.validation.min !== void 0) base.minLength = sp.validation.min;
411
- if (sp.validation.max !== void 0) base.maxLength = sp.validation.max;
412
- if (sp.validation.length !== void 0) {
413
- base.minLength = sp.validation.length;
414
- base.maxLength = sp.validation.length;
415
- }
416
- if (sp.validation.matches !== void 0) base.pattern = String(sp.validation.matches);
417
- }
418
- if (sp.email) base.format = "email";
419
- if (sp.url) base.format = "uri";
420
- if (sp.storage) base.format = "uri";
421
- return base;
422
- }
423
- case "number": {
424
- const np = property;
425
- base.type = np.validation?.integer || np.columnType === "integer" || np.columnType === "serial" || np.columnType === "bigserial" || np.columnType === "bigint" ? "integer" : "number";
426
- if (np.enum) {
427
- const enumValues = resolveEnumValues(np.enum);
428
- if (enumValues.length > 0) base.enum = enumValues;
429
- }
430
- if (np.validation) {
431
- if (np.validation.min !== void 0) base.minimum = np.validation.min;
432
- if (np.validation.max !== void 0) base.maximum = np.validation.max;
433
- if (np.validation.moreThan !== void 0) {
434
- base.minimum = np.validation.moreThan;
435
- base.exclusiveMinimum = true;
436
- }
437
- if (np.validation.lessThan !== void 0) {
438
- base.maximum = np.validation.lessThan;
439
- base.exclusiveMaximum = true;
440
- }
441
- }
442
- return base;
443
- }
444
- case "boolean":
445
- base.type = "boolean";
446
- return base;
447
- case "date":
448
- base.type = "string";
449
- if (property.mode === "date") base.format = "date";
450
- else base.format = "date-time";
451
- if (property.autoValue) {
452
- base.readOnly = true;
453
- base.description = (base.description || "") + (property.autoValue === "on_create" ? " (Auto-set on creation)" : " (Auto-updated)");
454
- }
455
- return base;
456
- case "geopoint":
457
- base.type = "object";
458
- base.properties = {
459
- latitude: { type: "number" },
460
- longitude: { type: "number" }
461
- };
462
- base.required = ["latitude", "longitude"];
463
- return base;
464
- case "reference":
465
- base.type = "string";
466
- base.description = (base.description || "") + " (Reference ID)";
467
- return base;
468
- case "array": {
469
- const ap = property;
470
- base.type = "array";
471
- if (ap.oneOf) {
472
- const typeField = ap.oneOf.typeField || "type";
473
- const valueField = ap.oneOf.valueField || "value";
474
- const variants = [];
475
- for (const [variantKey, variantProp] of Object.entries(ap.oneOf.properties)) variants.push({
476
- type: "object",
477
- properties: {
478
- [typeField]: {
479
- type: "string",
480
- enum: [variantKey]
481
- },
482
- [valueField]: convertPropertyToSchema(variantProp)
483
- },
484
- required: [typeField, valueField]
485
- });
486
- base.items = { oneOf: variants };
487
- } else if (ap.of) if (Array.isArray(ap.of)) base.items = { oneOf: ap.of.map((p) => convertPropertyToSchema(p)) };
488
- else base.items = convertPropertyToSchema(ap.of);
489
- else base.items = {};
490
- if (ap.validation) {
491
- if (ap.validation.min !== void 0) base.minItems = ap.validation.min;
492
- if (ap.validation.max !== void 0) base.maxItems = ap.validation.max;
493
- }
494
- return base;
495
- }
496
- case "map": {
497
- const mp = property;
498
- base.type = "object";
499
- if (mp.properties) {
500
- const props = {};
501
- const req = [];
502
- for (const [key, subProp] of Object.entries(mp.properties)) {
503
- props[key] = convertPropertyToSchema(subProp);
504
- if (subProp.validation?.required) req.push(key);
505
- }
506
- base.properties = props;
507
- if (req.length > 0) base.required = req;
508
- } else if (mp.keyValue) base.additionalProperties = true;
509
- return base;
510
- }
511
- case "vector": {
512
- const vp = property;
513
- base.type = "array";
514
- base.items = { type: "number" };
515
- base.description = (base.description || "") + ` (Vector(${vp.dimensions}))`;
516
- return base;
517
- }
518
- case "binary":
519
- base.type = "string";
520
- base.description = (base.description || "") + " (Binary/Base64)";
521
- return base;
522
- default:
523
- base.type = "string";
524
- return base;
525
- }
526
- }
527
- /**
528
- * Resolve EnumValues (array or record) into a flat array of enum values.
529
- */
530
- function resolveEnumValues(enumDef) {
531
- if (Array.isArray(enumDef)) return enumDef.map((e) => typeof e === "object" && e !== null && "id" in e ? e.id : e);
532
- return Object.keys(enumDef).map((k) => {
533
- const num = Number(k);
534
- return isNaN(num) ? k : num;
535
- });
536
- }
537
- /**
538
- * Build PostgREST-style filter parameters for a collection.
539
- * These are additional query parameters like `?status=eq.active&price=gte.100`.
540
- */
541
- function buildFilterParameters(collection) {
542
- const params = [];
543
- for (const [key, property] of Object.entries(collection.properties)) {
544
- if (property.type === "relation" || property.type === "map" || property.type === "array" || property.type === "geopoint") continue;
545
- params.push({
546
- name: key,
547
- in: "query",
548
- required: false,
549
- schema: { type: "string" },
550
- description: `Filter by \`${key}\`. Supports PostgREST operators: \`eq.value\`, \`neq.value\`, \`gt.value\`, \`gte.value\`, \`lt.value\`, \`lte.value\`, \`in.(a,b,c)\`, \`nin.(a,b,c)\`, \`cs.value\` (array-contains), \`csa.(a,b)\` (array-contains-any). Plain values imply equality.`,
551
- example: property.type === "string" ? "eq.active" : property.type === "number" ? "gte.100" : void 0
552
- });
553
- }
554
- return params;
555
- }
556
- /**
557
- * Standard error responses included on every endpoint.
558
- */
559
- function errorResponses(requireAuth) {
560
- const responses = {
561
- 400: {
562
- description: "Bad request",
563
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
564
- },
565
- 500: {
566
- description: "Internal server error",
567
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
568
- }
569
- };
570
- if (requireAuth) {
571
- responses[401] = {
572
- description: "Authentication required or invalid token",
573
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
574
- };
575
- responses[403] = {
576
- description: "Insufficient permissions",
577
- content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
578
- };
579
- }
580
- return responses;
581
- }
582
- /**
583
- * Prefix a noun with "a" or "an" based on its leading sound.
584
- */
585
- function withIndefiniteArticle(noun) {
586
- return `${/^[aeiou]/i.test(noun) ? "an" : "a"} ${noun}`;
587
- }
588
- /**
589
- * Convert a string to PascalCase for schema names.
590
- */
591
- function toPascalCase(str) {
592
- return str.replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
593
- }
594
- //#endregion
595
- export { generateOpenApiSpec };
596
-
597
- //# sourceMappingURL=openapi-generator-BEwyiaAr.js.map