appos 0.3.2-0 → 0.3.3-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/bin/auth-schema-CcqAJY9P.mjs +2 -0
  2. package/dist/bin/better-sqlite3-CuQ3hsWl.mjs +2 -0
  3. package/dist/bin/bun-sql-DGeo-s_M.mjs +2 -0
  4. package/dist/bin/cache-3oO07miM.mjs +2 -0
  5. package/dist/bin/chunk-l9p7A9gZ.mjs +2 -0
  6. package/dist/bin/cockroach-BaICwY7N.mjs +2 -0
  7. package/dist/bin/database-CaysWPpa.mjs +2 -0
  8. package/dist/bin/esm-BvsccvmM.mjs +2 -0
  9. package/dist/bin/esm-CGKzJ7Am.mjs +3 -0
  10. package/dist/bin/event-DnSe3eh0.mjs +8 -0
  11. package/dist/bin/extract-blob-metadata-iqwTl2ft.mjs +170 -0
  12. package/dist/bin/generate-image-variant-Lyx0vhM6.mjs +2 -0
  13. package/dist/bin/generate-preview-0MrKxslA.mjs +2 -0
  14. package/dist/bin/libsql-DQJrZsU9.mjs +2 -0
  15. package/dist/bin/logger-BAGZLUzj.mjs +2 -0
  16. package/dist/bin/main.mjs +1201 -190
  17. package/dist/bin/migrator-B7iNKM8N.mjs +2 -0
  18. package/dist/bin/migrator-BKE1cSQQ.mjs +2 -0
  19. package/dist/bin/migrator-BXcbc9zs.mjs +2 -0
  20. package/dist/bin/migrator-B_XhRWZC.mjs +8 -0
  21. package/dist/bin/migrator-Bz52Gtr8.mjs +2 -0
  22. package/dist/bin/migrator-C7W-cZHB.mjs +2 -0
  23. package/dist/bin/migrator-CEnKyGSW.mjs +2 -0
  24. package/dist/bin/migrator-CHzIIl5X.mjs +2 -0
  25. package/dist/bin/migrator-CR-rjZdM.mjs +2 -0
  26. package/dist/bin/migrator-CjIr1ZCx.mjs +8 -0
  27. package/dist/bin/migrator-Cuubh2dg.mjs +2 -0
  28. package/dist/bin/migrator-D8m-ORbr.mjs +8 -0
  29. package/dist/bin/migrator-DBFwrhZH.mjs +2 -0
  30. package/dist/bin/migrator-DLmhW9u_.mjs +2 -0
  31. package/dist/bin/migrator-DLoHx807.mjs +4 -0
  32. package/dist/bin/migrator-DtN_iS87.mjs +2 -0
  33. package/dist/bin/migrator-Yc57lb3w.mjs +2 -0
  34. package/dist/bin/migrator-cEVXH3xC.mjs +2 -0
  35. package/dist/bin/migrator-hWi-sYIq.mjs +2 -0
  36. package/dist/bin/mysql2-DufFWkj4.mjs +2 -0
  37. package/dist/bin/neon-serverless-5a4h2VFz.mjs +2 -0
  38. package/dist/bin/node-CiOp4xrR.mjs +22 -0
  39. package/dist/bin/node-mssql-DvZGaUkB.mjs +322 -0
  40. package/dist/bin/node-postgres-BqbJVBQY.mjs +2 -0
  41. package/dist/bin/node-postgres-DnhRTTO8.mjs +2 -0
  42. package/dist/bin/open-0ksnL0S8.mjs +2 -0
  43. package/dist/bin/pdf-sUYeFPr4.mjs +14 -0
  44. package/dist/bin/pg-CaH8ptj-.mjs +2 -0
  45. package/dist/bin/pg-core-BLTZt9AH.mjs +8 -0
  46. package/dist/bin/pg-core-CGzidKaA.mjs +2 -0
  47. package/dist/bin/pglite-BJB9z7Ju.mjs +2 -0
  48. package/dist/bin/planetscale-serverless-H3RfLlMK.mjs +13 -0
  49. package/dist/bin/postgres-js-DuOf1eWm.mjs +2 -0
  50. package/dist/bin/purge-attachment-DQXpTtTx.mjs +2 -0
  51. package/dist/bin/purge-audit-logs-BEt2J2gD.mjs +2 -0
  52. package/dist/bin/{purge-unattached-blobs-Duvv8Izd.mjs → purge-unattached-blobs-DOmk4ddJ.mjs} +1 -1
  53. package/dist/bin/query-builder-DSRrR6X_.mjs +8 -0
  54. package/dist/bin/query-builder-V8-LDhvA.mjs +3 -0
  55. package/dist/bin/session-CdB1A-LB.mjs +14 -0
  56. package/dist/bin/session-Cl2e-_i8.mjs +8 -0
  57. package/dist/bin/singlestore-COft6TlR.mjs +8 -0
  58. package/dist/bin/sql-D-eKV1Dn.mjs +2 -0
  59. package/dist/bin/sqlite-cloud-Co9jOn5G.mjs +2 -0
  60. package/dist/bin/sqlite-proxy-Cpu78gJF.mjs +2 -0
  61. package/dist/bin/src-C-oXmCzx.mjs +6 -0
  62. package/dist/bin/table-3zUpWkMg.mjs +2 -0
  63. package/dist/bin/track-db-changes-DWyY5jXm.mjs +2 -0
  64. package/dist/bin/utils-CyoeCJlf.mjs +2 -0
  65. package/dist/bin/utils-EoqYQKy1.mjs +2 -0
  66. package/dist/bin/utils-bsypyqPl.mjs +2 -0
  67. package/dist/bin/vercel-postgres-HWL6xtqi.mjs +2 -0
  68. package/dist/bin/workflow-zxHDyfLq.mjs +2 -0
  69. package/dist/bin/youch-handler-DrYdbUhe.mjs +2 -0
  70. package/dist/bin/zod-MJjkEkRY.mjs +24 -0
  71. package/dist/exports/api/_virtual/rolldown_runtime.mjs +36 -1
  72. package/dist/exports/api/app-context.mjs +24 -1
  73. package/dist/exports/api/auth-schema.mjs +373 -1
  74. package/dist/exports/api/auth.d.mts +4 -0
  75. package/dist/exports/api/auth.mjs +188 -1
  76. package/dist/exports/api/cache.d.mts +2 -2
  77. package/dist/exports/api/cache.mjs +28 -1
  78. package/dist/exports/api/config.mjs +72 -1
  79. package/dist/exports/api/constants.mjs +92 -1
  80. package/dist/exports/api/container.mjs +49 -1
  81. package/dist/exports/api/database.mjs +218 -1
  82. package/dist/exports/api/event.mjs +236 -1
  83. package/dist/exports/api/i18n.mjs +45 -1
  84. package/dist/exports/api/index.mjs +20 -1
  85. package/dist/exports/api/instrumentation.mjs +40 -1
  86. package/dist/exports/api/logger.mjs +26 -1
  87. package/dist/exports/api/mailer.mjs +37 -1
  88. package/dist/exports/api/middleware.mjs +73 -1
  89. package/dist/exports/api/openapi.mjs +507 -1
  90. package/dist/exports/api/orm.mjs +43 -1
  91. package/dist/exports/api/otel.mjs +56 -1
  92. package/dist/exports/api/redis.mjs +41 -1
  93. package/dist/exports/api/storage-schema.mjs +72 -1
  94. package/dist/exports/api/storage.mjs +833 -1
  95. package/dist/exports/api/web/auth.mjs +17 -1
  96. package/dist/exports/api/workflow.mjs +196 -1
  97. package/dist/exports/api/workflows/_virtual/rolldown_runtime.mjs +36 -1
  98. package/dist/exports/api/workflows/api/auth-schema.mjs +373 -1
  99. package/dist/exports/api/workflows/api/auth.d.mts +4 -0
  100. package/dist/exports/api/workflows/api/cache.d.mts +2 -2
  101. package/dist/exports/api/workflows/api/event.mjs +126 -1
  102. package/dist/exports/api/workflows/api/redis.mjs +3 -1
  103. package/dist/exports/api/workflows/api/workflow.mjs +135 -1
  104. package/dist/exports/api/workflows/constants.mjs +23 -1
  105. package/dist/exports/api/workflows/extract-blob-metadata.mjs +132 -1
  106. package/dist/exports/api/workflows/generate-image-variant.d.mts +2 -2
  107. package/dist/exports/api/workflows/generate-image-variant.mjs +118 -1
  108. package/dist/exports/api/workflows/generate-preview.mjs +160 -1
  109. package/dist/exports/api/workflows/index.mjs +3 -1
  110. package/dist/exports/api/workflows/purge-attachment.mjs +34 -1
  111. package/dist/exports/api/workflows/purge-audit-logs.mjs +47 -1
  112. package/dist/exports/api/workflows/purge-unattached-blobs.mjs +46 -1
  113. package/dist/exports/api/workflows/track-db-changes.mjs +110 -1
  114. package/dist/exports/cli/_virtual/rolldown_runtime.mjs +36 -1
  115. package/dist/exports/cli/api/auth-schema.mjs +373 -1
  116. package/dist/exports/cli/api/auth.d.mts +4 -0
  117. package/dist/exports/cli/api/cache.d.mts +2 -2
  118. package/dist/exports/cli/api/event.mjs +126 -1
  119. package/dist/exports/cli/api/redis.mjs +3 -1
  120. package/dist/exports/cli/api/workflow.mjs +135 -1
  121. package/dist/exports/cli/api/workflows/extract-blob-metadata.mjs +132 -1
  122. package/dist/exports/cli/api/workflows/generate-image-variant.mjs +118 -1
  123. package/dist/exports/cli/api/workflows/generate-preview.mjs +160 -1
  124. package/dist/exports/cli/api/workflows/purge-attachment.mjs +34 -1
  125. package/dist/exports/cli/api/workflows/purge-audit-logs.mjs +47 -1
  126. package/dist/exports/cli/api/workflows/purge-unattached-blobs.mjs +46 -1
  127. package/dist/exports/cli/api/workflows/track-db-changes.mjs +110 -1
  128. package/dist/exports/cli/command.d.mts +2 -0
  129. package/dist/exports/cli/command.mjs +43 -1
  130. package/dist/exports/cli/constants.mjs +23 -1
  131. package/dist/exports/cli/index.mjs +3 -1
  132. package/dist/exports/devtools/index.js +4 -1
  133. package/dist/exports/tests/api/auth.d.mts +4 -0
  134. package/dist/exports/tests/api/cache.d.mts +2 -2
  135. package/dist/exports/tests/api/middleware/i18n.mjs +1 -1
  136. package/dist/exports/tests/api/middleware/youch-handler.mjs +1 -1
  137. package/dist/exports/tests/api/openapi.mjs +1 -1
  138. package/dist/exports/tests/api/server.mjs +1 -1
  139. package/dist/exports/tests/constants.mjs +1 -1
  140. package/dist/exports/vendors/date.js +1 -1
  141. package/dist/exports/vendors/toolkit.js +1 -1
  142. package/dist/exports/vendors/zod.js +1 -1
  143. package/dist/exports/vitest/globals.mjs +1 -1
  144. package/dist/exports/web/auth.js +75 -1
  145. package/dist/exports/web/i18n.js +45 -1
  146. package/dist/exports/web/index.js +8 -1
  147. package/package.json +19 -17
  148. package/dist/bin/auth-schema-Va0CYicu.mjs +0 -2
  149. package/dist/bin/event-8JibGFH_.mjs +0 -2
  150. package/dist/bin/extract-blob-metadata-DjPfHtQ2.mjs +0 -2
  151. package/dist/bin/generate-image-variant-D5VDFyWj.mjs +0 -2
  152. package/dist/bin/generate-preview-Dssw7w5U.mjs +0 -2
  153. package/dist/bin/purge-attachment-BBPzIxwt.mjs +0 -2
  154. package/dist/bin/purge-audit-logs-BeZy3IFM.mjs +0 -2
  155. package/dist/bin/track-db-changes-CFykw_YO.mjs +0 -2
  156. package/dist/bin/workflow-BNUZrj4F.mjs +0 -2
  157. package/dist/bin/youch-handler-BadUgHb0.mjs +0 -2
@@ -10,6 +10,7 @@ import { z } from "zod";
10
10
  interface Command<C extends Container, A = readonly unknown[], O = Record<string, unknown>> {
11
11
  aliases: string[];
12
12
  description: string;
13
+ devOnly: boolean;
13
14
  args: z.ZodTuple<readonly [z.ZodTypeAny, ...z.ZodTypeAny[]], z.ZodTypeAny | null> | z.ZodArray<z.ZodTypeAny>;
14
15
  opts: z.ZodObject<z.ZodRawShape>;
15
16
  run: (ctx: CommandContext<C, A, O>) => Promise<void>;
@@ -46,6 +47,7 @@ interface Command<C extends Container, A = readonly unknown[], O = Record<string
46
47
  declare function defineCommand<C extends Container = Container, ASchema extends z.ZodSchema<unknown> | undefined = undefined, OSchema extends z.ZodSchema<unknown> | undefined = undefined>(def: {
47
48
  aliases?: string[];
48
49
  description: string;
50
+ devOnly?: boolean;
49
51
  args: ASchema;
50
52
  opts: OSchema;
51
53
  run: (ctx: CommandContext<C, ASchema extends z.ZodSchema<infer A> ? A : readonly unknown[], OSchema extends z.ZodSchema<infer O> ? O : Record<string, unknown>>) => Promise<void>;
@@ -1 +1,43 @@
1
- function e(e){return{aliases:e.aliases||[],description:e.description,args:e.args||[],opts:e.opts||{},run:e.run}}export{e as defineCommand};
1
+ //#region src/cli/command.ts
2
+ /**
3
+ * Define a CLI command with type-safe arguments and options.
4
+ *
5
+ * The command name is automatically derived from the filename relative to the commands directory:
6
+ * - `<APPOS_DIR>/<COMMANDS_DIR>/db/push.ts` → `db:push`
7
+ * - `<APPOS_DIR>/<COMMANDS_DIR>/dev.ts` → `dev`
8
+ *
9
+ * Where:
10
+ * - `APPOS_DIR` defaults to "appos" (see constants.ts)
11
+ * - `COMMANDS_DIR` defaults to "commands" (see constants.ts)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // appos/commands/db/migrate.ts
16
+ * import { defineCommand } from "appos/cli";
17
+ * import { z } from "appos/zod";
18
+ *
19
+ * export default defineCommand({
20
+ * description: "Run database migrations",
21
+ * args: z.tuple([]),
22
+ * opts: z.object({
23
+ * dry: z.boolean().default(false)
24
+ * }),
25
+ * async run(args, opts, container) {
26
+ * await container.db.primary.migrate({ dryRun: opts.dry });
27
+ * }
28
+ * });
29
+ * ```
30
+ */
31
+ function defineCommand(def) {
32
+ return {
33
+ aliases: def.aliases || [],
34
+ description: def.description,
35
+ devOnly: def.devOnly ?? false,
36
+ args: def.args || [],
37
+ opts: def.opts || {},
38
+ run: def.run
39
+ };
40
+ }
41
+
42
+ //#endregion
43
+ export { defineCommand };
@@ -1 +1,23 @@
1
- process.env.NODE_ENV;export{};
1
+ //#region src/constants.ts
2
+ /**
3
+ * Directory for public static assets.
4
+ *
5
+ * Expected structure:
6
+ * - `<project-root>/public/` - Public directory root
7
+ * - `<project-root>/public/locales/` - i18n translation files
8
+ *
9
+ * @default "public"
10
+ */
11
+ const PUBLIC_DIR = process.env.NODE_ENV === "production" ? "client" : "public";
12
+ /**
13
+ * File extension for code files based on environment.
14
+ *
15
+ * In development: `.ts` (TypeScript source files)
16
+ * In production: `.js` (bundled JavaScript files)
17
+ *
18
+ * @default "ts" in development, "js" in production
19
+ */
20
+ const FILE_EXT = process.env.NODE_ENV === "production" ? "js" : "ts";
21
+
22
+ //#endregion
23
+ export { };
@@ -1 +1,3 @@
1
- import{defineCommand as e}from"./command.mjs";export{e as defineCommand};
1
+ import { defineCommand } from "./command.mjs";
2
+
3
+ export { defineCommand };
@@ -1 +1,4 @@
1
- import{ReactQueryDevtools as e}from"@tanstack/react-query-devtools";import{TanStackRouterDevtools as t}from"@tanstack/react-router-devtools";export{e as ReactQueryDevtools,t as TanStackRouterDevtools};
1
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
2
+ import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
3
+
4
+ export { ReactQueryDevtools, TanStackRouterDevtools };
@@ -370,6 +370,10 @@ type DefineAuthOptions<T extends AuthConfig, TDb = unknown> = {
370
370
  * Hooks for email sending and OTP delivery.
371
371
  */
372
372
  hooks: RequiredHooks<T>;
373
+ /**
374
+ * Secret key for signing tokens and cookies.
375
+ */
376
+ secret: string;
373
377
  /**
374
378
  * Session configuration.
375
379
  */
@@ -1,5 +1,5 @@
1
1
  import { Logger } from "./logger.mjs";
2
- import * as keyv0 from "keyv";
2
+ import * as _keyv_redis0 from "@keyv/redis";
3
3
  import { KeyvRedisOptions } from "@keyv/redis";
4
4
 
5
5
  //#region src/api/cache.d.ts
@@ -39,6 +39,6 @@ declare function defineCache({
39
39
  url,
40
40
  logger,
41
41
  options
42
- }: DefineCacheOptions): keyv0.Keyv<any>;
42
+ }: DefineCacheOptions): _keyv_redis0.Keyv<any>;
43
43
  //#endregion
44
44
  export { Cache, DefineCacheOptions, defineCache };
@@ -1 +1 @@
1
- function e(e){return(t,n,r)=>{let i=t.headers[`accept-language`],a=`en`;if(i){let e=i.split(`,`)[0].split(`;`)[0].trim();e&&e.length>0&&(a=e)}t.dir=e.dir(a),t.language=a,t.languages=e.languages,t.t=e.getFixedT(a),r()}}export{e as defineI18nMiddleware};
1
+ function e(e){let t=process.env.NODE_ENV===`production`?new Map:null;return(n,r,i)=>{let a=n.headers[`accept-language`],o=`en`;if(a){let e=a.split(`,`)[0].split(`;`)[0].trim();e&&e.length>0&&(o=e)}if(n.dir=e.dir(o),n.language=o,n.languages=e.languages,t){let r=t.get(o);r||(r=e.getFixedT(o),t.set(o,r)),n.t=r}else n.t=e.getFixedT(o);i()}}export{e as defineI18nMiddleware};
@@ -1 +1 @@
1
- function e(e){if(e&&typeof e==`object`&&`status`in e){let t=e.status;if(typeof t==`number`)return t}return e instanceof SyntaxError?400:500}function t(t,n={}){return async(r,i,a,o)=>{if(process.env.NODE_ENV===`production`)return o(r);try{let{default:t}=await import(`youch`),o=new t(r,i);o.addLink(e=>`<a href="${`https://stackoverflow.com/search?q=${encodeURIComponent(e)}`}" target="_blank" title="Search on StackOverflow">Search Stack Overflow</a>`),o.addLink(e=>`<a href="${`https://www.google.com/search?q=${encodeURIComponent(e)}`}" target="_blank" title="Search on Google">Search Google</a>`);let s=await o.toHTML().then(e=>n.theme===`dark`?e.replace(`<style>`,`<style>body { background: #1a1a1a; color: #f0f0f0; }`):e);a.writeHead(e(r),{"content-type":`text/html`}),a.end(s)}catch(n){t.error({error:n instanceof Error?n.message:n,originalError:r instanceof Error?r.message:r},`Failed to render Youch error page`),a.status(e(r)).json({error:{message:r instanceof Error?r.message:`Internal server error`,...process.env.NODE_ENV!==`production`&&{stack:r instanceof Error?r.stack:void 0}}})}}}export{t as defineYouchErrorHandler};
1
+ function e(e){if(e&&typeof e==`object`&&`status`in e){let t=e.status;if(typeof t==`number`)return t}return e instanceof SyntaxError?400:500}function t(t,n={}){return async(r,i,a,o)=>{if(process.env.NODE_ENV===`production`)return o(r);try{let{Youch:t}=await import(`youch`),i=await new t().toHTML(r,{title:n.displayName||`Error`,ide:`vscode`});a.writeHead(e(r),{"content-type":`text/html`}),a.end(i)}catch(n){t.error({error:n instanceof Error?n.message:n,originalError:r instanceof Error?r.message:r},`Failed to render Youch error page`),a.status(e(r)).json({error:{message:r instanceof Error?r.message:`Internal server error`,...process.env.NODE_ENV!==`production`&&{stack:r instanceof Error?r.stack:void 0}}})}}}export{t as defineYouchErrorHandler};
@@ -1 +1 @@
1
- import{APPOS_DIR as e,FILE_EXT as t,PUBLIC_DIR as n,ROUTES_DIR as r}from"../constants.mjs";import"./app-context.mjs";import{access as i,mkdir as a,writeFile as o}from"node:fs/promises";import{join as s,resolve as c}from"node:path";import{remixRoutesOptionAdapter as l}from"@react-router/remix-routes-option-adapter";import{isEmpty as u}from"es-toolkit/compat";import{flatRoutes as d}from"remix-flat-routes";import{z as f}from"zod";import{createDocument as p}from"zod-openapi";const m=c(n,`openapi`);function h(e){return e.match(/^\/(v\d+)/)?.[1]}function g(e){return e.replace(/:(\w+)/g,`{$1}`)}function _(e,t){let n=g(e),r={summary:t.summary,description:t.description};(t.request?.params||t.request?.query||t.request?.headers)&&(r.requestParams={},t.request.params&&(r.requestParams.path=t.request.params),t.request.query&&(r.requestParams.query=t.request.query),t.request.headers&&(r.requestParams.header=t.request.headers)),t.request?.body&&(r.requestBody={content:{"application/json":{schema:t.request.body}}}),r.responses={};for(let[e,n]of Object.entries(t.responses))r.responses[e]={description:n.description,content:{"application/json":{schema:n.content[`application/json`].schema}}};return{path:n,config:r}}function v(e,t,n){let r={};for(let n of e){if(n.version!==t)continue;let e=n.path.replace(`/${t}`,``)||`/`;for(let t of n.openAPISpec){let{path:n,config:i}=_(e,t);r[n]||(r[n]={}),r[n][t.method]=i}}return p({openapi:`3.1.0`,info:n?.info||{title:`API ${t.toUpperCase()}`,version:t.replace(`v`,``),description:`OpenAPI specification for ${t} API`},servers:n?.servers||[{url:`http://localhost:8000/${t}`,description:process.env.NODE_ENV===`production`?`Production server`:`Development server`}],paths:r})}async function y(t){let n=c(e,r);try{await i(n)}catch(e){return t.logger.error({error:e},`OpenAPI routes directory not found`),[]}let a=await l(t=>d(r,t,{appDir:e,ignoredRouteFiles:[`**/.*`,`**/*.{spec,test}.{ts,tsx}`,`**/*-????????.{js,ts}`]})),o=[];for(let[n,r]of Object.entries(a)){let n=c(e,r.file).replace(/.ts$/,process.env.NODE_ENV===`production`?`.js`:`.ts`);try{let i=(await import(n)).default;if(!i||u(i)||/\/openapi.(j|t)s$/.test(n))continue;if(!i?.handlers&&!i?.openAPISpec){t.logger.warn(`Missing default export with 'defineOpenAPI' for '${e}/${r.file}'`);continue}let a=`/${r.path}`;o.push({path:a,filePath:n,handlers:i.handlers,openAPISpec:i.openAPISpec,version:h(a)})}catch(e){t.logger.error(e,`Error loading route ${r.file}:`)}}return o}function b(e,t){for(let n of t)for(let[t,r]of Object.entries(n.handlers))e[t.toLowerCase()](n.path,r)}async function x(n,i){let a=c(e,r,`${i}+/openapi.${t}`);try{let e=(await import(a)).default;return e?e(n):void 0}catch{return}}async function S(e,t){let n=[...new Set(t.map(e=>e.version).filter(Boolean))];n.length>0&&await a(m,{recursive:!0});for(let r of n){let n=v(t,r,await x(e,r));await o(s(m,`${r}.json`),JSON.stringify(n,null,2),`utf-8`)}}async function C(e){let t=await y(e.locals.container);b(e,t),process.env.NODE_ENV!==`production`&&await S(e.locals.container,t)}export{C as loadAndRegisterAPIRoutes};
1
+ import{APPOS_DIR as e,FILE_EXT as t,PUBLIC_DIR as n,ROUTES_DIR as r}from"../constants.mjs";import"./app-context.mjs";import{access as i,mkdir as a,writeFile as o}from"node:fs/promises";import{join as s,resolve as c}from"node:path";import{remixRoutesOptionAdapter as l}from"@react-router/remix-routes-option-adapter";import{isEmpty as u}from"es-toolkit/compat";import{flatRoutes as d}from"remix-flat-routes";import{z as f}from"zod";import{createDocument as p}from"zod-openapi";const m=c(n,`openapi`);function h(e){return e.match(/^\/(v\d+)/)?.[1]}function g(e){return e.replace(/:(\w+)/g,`{$1}`)}function _(e,t){let n=g(e),r={summary:t.summary,description:t.description};(t.request?.params||t.request?.query||t.request?.headers)&&(r.requestParams={},t.request.params&&(r.requestParams.path=t.request.params),t.request.query&&(r.requestParams.query=t.request.query),t.request.headers&&(r.requestParams.header=t.request.headers)),t.request?.body&&(r.requestBody={content:{"application/json":{schema:t.request.body}}}),r.responses={};for(let[e,n]of Object.entries(t.responses))r.responses[e]={description:n.description,content:{"application/json":{schema:n.content[`application/json`].schema}}};return{path:n,config:r}}function v(e,t,n){let r={};for(let n of e){if(n.version!==t)continue;let e=n.path.replace(`/${t}`,``)||`/`;for(let t of n.openAPISpec){let{path:n,config:i}=_(e,t);r[n]||(r[n]={}),r[n][t.method]=i}}return p({openapi:`3.1.0`,info:n?.info||{title:`API ${t.toUpperCase()}`,version:t.replace(`v`,``),description:`OpenAPI specification for ${t} API`},servers:n?.servers||[{url:`http://localhost:8000/${t}`,description:process.env.NODE_ENV===`production`?`Production server`:`Development server`}],paths:r})}async function y(n){let a=c(e,r);try{await i(a)}catch(e){return n.logger.error({error:e},`OpenAPI routes directory not found`),[]}let o=await l(t=>d(r,t,{appDir:e,ignoredRouteFiles:[`**/.*`,`**/*.{spec,test}.{ts,tsx}`,`**/*-????????.{js,ts}`]})),s=[];for(let[r,i]of Object.entries(o)){let r=c(e,i.file).replace(/\.ts$/,`.${t}`);try{let t=(await import(r)).default;if(!t||u(t)||/\/openapi.(j|t)s$/.test(r))continue;if(!t?.handlers&&!t?.openAPISpec){n.logger.warn(`Missing default export with 'defineOpenAPI' for '${e}/${i.file}'`);continue}let a=`/${i.path}`;s.push({path:a,filePath:r,handlers:t.handlers,openAPISpec:t.openAPISpec,version:h(a)})}catch(e){n.logger.error(e,`Error loading route ${i.file}:`)}}return s}function b(e,t){for(let n of t)for(let[t,r]of Object.entries(n.handlers))e[t.toLowerCase()](n.path,r)}async function x(n,i){let a=c(e,r,`${i}+/openapi.${t}`);try{let e=(await import(a)).default;return e?e(n):void 0}catch{return}}async function S(e,t){let n=[...new Set(t.map(e=>e.version).filter(Boolean))];n.length>0&&await a(m,{recursive:!0});for(let r of n){let n=v(t,r,await x(e,r));await o(s(m,`${r}.json`),JSON.stringify(n,null,2),`utf-8`)}}async function C(e){let t=await y(e.locals.container);b(e,t),process.env.NODE_ENV!==`production`&&await S(e.locals.container,t)}export{C as loadAndRegisterAPIRoutes};
@@ -1 +1 @@
1
- import{PUBLIC_DIR as e}from"../constants.mjs";import{defineErrorHandlerMiddleware as t}from"./middleware/error-handler.mjs";import{defineHealthMiddleware as n}from"./middleware/health.mjs";import{defineI18nMiddleware as r}from"./middleware/i18n.mjs";import{defineRequestLoggerMiddleware as i}from"./middleware/request-logger.mjs";import{defineShutdownMiddleware as a}from"./middleware/shutdown.mjs";import{defineTimeoutMiddleware as o}from"./middleware/timeout.mjs";import{loadMiddleware as s}from"./middleware.mjs";import{loadAndRegisterAPIRoutes as c}from"./openapi.mjs";import{join as l,resolve as u}from"node:path";import{toNodeHandler as d}from"better-auth/node";import f from"cors";import{rateLimit as p}from"express-rate-limit";import m from"helmet";import{RedisStore as h}from"rate-limit-redis";import{createClient as g}from"redis";import _ from"ultimate-express";async function v({container:v}){let y=!1,{host:b=`0.0.0.0`,port:x,timeout:S=3e4,bodyLimit:C=`1mb`,healthPath:w=`/health`,cors:T,helmet:E,rateLimit:D,redisUrl:O}=v.server,k=_();k.locals.container=v;let A=null;if(O&&D)try{A=g({url:O}),A.on(`error`,e=>{v.logger.error({error:e.message},`Redis client error`)}),await A.connect(),v.logger.info(`Connected to Redis for rate limiting`)}catch(e){v.logger.error({error:e instanceof Error?e.message:e},`Failed to connect to Redis, falling back to in-memory rate limiting`),A=null}if(k.use(a(v.logger,()=>y),o(v.logger,S),i(v.logger),n(w)),E!==void 0&&k.use(m(E)),T!==void 0&&k.use(f(T)),D)for(let[e,t]of D.entries()){let n=p({windowMs:t.windowMs??60*1e3,limit:t.limit??100,standardHeaders:t.standardHeaders??`draft-8`,legacyHeaders:t.legacyHeaders??!1,skip:t.skip,keyGenerator:t.keyGenerator,handler:t.handler,message:t.message,statusCode:t.statusCode,requestPropertyName:t.requestPropertyName,skipFailedRequests:t.skipFailedRequests,skipSuccessfulRequests:t.skipSuccessfulRequests,requestWasSuccessful:t.requestWasSuccessful,validate:t.validate,store:A?new h({sendCommand:(...e)=>A.sendCommand(e),prefix:`rl:${e}:`}):t.store});k.use(n)}if(k.use(r(v.i18n),_.json({limit:C}),_.urlencoded({extended:!0,limit:C})),await s(l(process.cwd(),`api`,`middleware`),v,k),k.get(`/`,(e,t)=>{t.json({message:`${v.config.APP_NAME} server is running.`})}).all(`${v.auth.options.basePath}/*`,d(v.auth)),await c(k),k.use(_.static(u(e))),process.env.NODE_ENV!==`production`){let{defineYouchErrorHandler:e}=await import(`./middleware/youch-handler.mjs`);k.use(e(v.logger))}else k.use(t(v.logger));return{app:k,host:b,port:x,async start(){await new Promise((e,t)=>{try{k.listen(x,b,()=>{e()})}catch(e){t(e)}})},async close(){if(y=!0,k.uwsApp.close(),A)try{await A.destroy()}catch(e){v.logger.warn({error:e instanceof Error?e.message:e},`Error disconnecting from Redis`)}}}}export{v as defineServer};
1
+ import{APPOS_DIR as e,MIDDLEWARE_DIR as t,PUBLIC_DIR as n}from"../constants.mjs";import{defineErrorHandlerMiddleware as r}from"./middleware/error-handler.mjs";import{defineHealthMiddleware as i}from"./middleware/health.mjs";import{defineI18nMiddleware as a}from"./middleware/i18n.mjs";import{defineRequestLoggerMiddleware as o}from"./middleware/request-logger.mjs";import{defineShutdownMiddleware as s}from"./middleware/shutdown.mjs";import{defineTimeoutMiddleware as c}from"./middleware/timeout.mjs";import{loadMiddleware as l}from"./middleware.mjs";import{loadAndRegisterAPIRoutes as u}from"./openapi.mjs";import{join as d,resolve as f}from"node:path";import{toNodeHandler as p}from"better-auth/node";import m from"cors";import{rateLimit as h}from"express-rate-limit";import g from"helmet";import{RedisStore as _}from"rate-limit-redis";import{createClient as v}from"redis";import y from"ultimate-express";async function b({container:b}){let x=!1,{host:S=`0.0.0.0`,port:C,timeout:w=3e4,bodyLimit:T=`1mb`,healthPath:E=`/health`,cors:D,helmet:O,rateLimit:k,redisUrl:A}=b.server,j=y();j.disable(`x-powered-by`),j.locals.container=b;let M=null;if(A&&k)try{M=v({url:A}),M.on(`error`,e=>{b.logger.error({error:e.message},`Redis client error`)}),await M.connect(),b.logger.info(`Connected to Redis for rate limiting`)}catch(e){b.logger.error({error:e instanceof Error?e.message:e},`Failed to connect to Redis, falling back to in-memory rate limiting`),M=null}if(j.use(s(b.logger,()=>x),c(b.logger,w),o(b.logger),i(E)),O!==void 0&&j.use(g(O)),D!==void 0&&j.use(m(D)),k)for(let[e,t]of k.entries()){let n=h({windowMs:t.windowMs??60*1e3,limit:t.limit??100,standardHeaders:t.standardHeaders??`draft-8`,legacyHeaders:t.legacyHeaders??!1,skip:t.skip,keyGenerator:t.keyGenerator,handler:t.handler,message:t.message,statusCode:t.statusCode,requestPropertyName:t.requestPropertyName,skipFailedRequests:t.skipFailedRequests,skipSuccessfulRequests:t.skipSuccessfulRequests,requestWasSuccessful:t.requestWasSuccessful,validate:t.validate,store:M?new _({sendCommand:(...e)=>M.sendCommand(e),prefix:`rl:${e}:`}):t.store});j.use(n)}if(j.use(a(b.i18n),y.json({limit:T}),y.urlencoded({extended:!0,limit:T})),await l(d(process.cwd(),e,t),b,j),j.get(`/`,(e,t)=>{t.json({message:`${b.config.APP_NAME} server is running.`})}).all(`${b.auth.options.basePath}/*`,p(b.auth)),await u(j),j.use(y.static(f(n))),process.env.NODE_ENV!==`production`){let{defineYouchErrorHandler:e}=await import(`./middleware/youch-handler.mjs`);j.use(e(b.logger))}else j.use(r(b.logger));return{app:j,host:S,port:C,async start(){await new Promise((e,t)=>{try{j.listen(C,S,()=>{e()})}catch(e){t(e)}})},async close(){if(x=!0,j.uwsApp.close(),M)try{await M.destroy()}catch(e){b.logger.warn({error:e instanceof Error?e.message:e},`Error disconnecting from Redis`)}}}}export{b as defineServer};
@@ -1 +1 @@
1
- const e=`api`,t=`databases`,n=`routes`,r=`public`,i=process.env.NODE_ENV===`production`?`js`:`ts`;export{e as APPOS_DIR,t as DATABASES_DIR,i as FILE_EXT,r as PUBLIC_DIR,n as ROUTES_DIR};
1
+ const e=`api`,t=`databases`,n=`middleware`,r=`routes`,i=process.env.NODE_ENV===`production`?`client`:`public`,a=process.env.NODE_ENV===`production`?`js`:`ts`;export{e as APPOS_DIR,t as DATABASES_DIR,a as FILE_EXT,n as MIDDLEWARE_DIR,i as PUBLIC_DIR,r as ROUTES_DIR};
@@ -1 +1 @@
1
- export*from"date-fns";
1
+ export * from "date-fns"
@@ -1 +1 @@
1
- export*from"es-toolkit";
1
+ export * from "es-toolkit"
@@ -1 +1 @@
1
- export*from"zod";
1
+ export * from "zod"
@@ -1 +1 @@
1
- export*from"vitest/globals";export{};
1
+ export{};
@@ -1 +1,75 @@
1
- import{passkeyClient as e}from"@better-auth/passkey/client";import{ssoClient as t}from"@better-auth/sso/client";import{adminClient as n,anonymousClient as r,apiKeyClient as i,emailOTPClient as a,magicLinkClient as o,multiSessionClient as s,phoneNumberClient as c,twoFactorClient as l,usernameClient as u}from"better-auth/client/plugins";import{createAuthClient as d}from"better-auth/react";const f=`/auth`,p=``;function m(e){return{emailPassword:e.methods?.emailPassword!==void 0,magicLink:e.methods?.magicLink!==void 0,passkey:e.methods?.passkey!==void 0,phoneOtp:e.methods?.phoneOtp!==void 0,emailOtp:e.methods?.emailOtp!==void 0,oauth:{google:e.oauth?.google===!0,github:e.oauth?.github===!0,apple:e.oauth?.apple===!0,facebook:e.oauth?.facebook===!0},twoFactor:{enabled:e.plugins?.twoFactor!==void 0,totp:e.plugins?.twoFactor?.totp!==void 0,otp:e.plugins?.twoFactor?.otp===!0,backupCodes:e.plugins?.twoFactor?.backupCodes!==void 0},multiSession:e.plugins?.multiSession!==void 0,username:e.plugins?.username!==void 0,anonymous:e.plugins?.anonymous!==void 0,sso:e.plugins?.sso!==void 0}}function h(f){let{config:p,baseURL:h,plugins:g}=f,_=[];return p.plugins?.admin&&_.push(n({ac:p.plugins.admin.ac,roles:p.plugins.admin.roles})),p.plugins?.apiKey&&_.push(i()),p.plugins?.twoFactor&&_.push(l({onTwoFactorRedirect:g?.twoFactor?.onTwoFactorRedirect})),p.methods?.passkey&&_.push(e()),p.methods?.magicLink&&_.push(o()),p.methods?.phoneOtp&&_.push(c()),p.methods?.emailOtp&&_.push(a()),p.plugins?.username&&_.push(u()),p.plugins?.anonymous&&_.push(r()),p.plugins?.multiSession&&_.push(s()),p.plugins?.sso&&_.push(t({domainVerification:p.plugins.sso.domainVerification?{enabled:!0}:void 0})),{client:d({baseURL:(h??p.baseURL??``)||void 0,plugins:_}),features:m(p)}}export{f as AUTH_BASE_PATH,p as AUTH_BASE_URL,h as defineAuthClient,m as defineAuthFeatures};
1
+ import { passkeyClient } from "@better-auth/passkey/client";
2
+ import { ssoClient } from "@better-auth/sso/client";
3
+ import { adminClient, anonymousClient, apiKeyClient, emailOTPClient, magicLinkClient, multiSessionClient, phoneNumberClient, twoFactorClient, usernameClient } from "better-auth/client/plugins";
4
+ import { createAuthClient } from "better-auth/react";
5
+
6
+ //#region src/web/auth.ts
7
+ /**
8
+ * Default base path for auth routes.
9
+ */
10
+ const AUTH_BASE_PATH = "/auth";
11
+ /**
12
+ * Default base URL (empty - same origin).
13
+ */
14
+ const AUTH_BASE_URL = "";
15
+ /**
16
+ * Derives features from config at runtime.
17
+ * Uses presence-based detection - if key exists, feature is enabled.
18
+ */
19
+ function defineAuthFeatures(config) {
20
+ return {
21
+ emailPassword: config.methods?.emailPassword !== void 0,
22
+ magicLink: config.methods?.magicLink !== void 0,
23
+ passkey: config.methods?.passkey !== void 0,
24
+ phoneOtp: config.methods?.phoneOtp !== void 0,
25
+ emailOtp: config.methods?.emailOtp !== void 0,
26
+ oauth: {
27
+ google: config.oauth?.google === true,
28
+ github: config.oauth?.github === true,
29
+ apple: config.oauth?.apple === true,
30
+ facebook: config.oauth?.facebook === true
31
+ },
32
+ twoFactor: {
33
+ enabled: config.plugins?.twoFactor !== void 0,
34
+ totp: config.plugins?.twoFactor?.totp !== void 0,
35
+ otp: config.plugins?.twoFactor?.otp === true,
36
+ backupCodes: config.plugins?.twoFactor?.backupCodes !== void 0
37
+ },
38
+ multiSession: config.plugins?.multiSession !== void 0,
39
+ username: config.plugins?.username !== void 0,
40
+ anonymous: config.plugins?.anonymous !== void 0,
41
+ sso: config.plugins?.sso !== void 0
42
+ };
43
+ }
44
+ /**
45
+ * Constructs Better Auth client from neutral config.
46
+ * Returns both client instance and derived features.
47
+ */
48
+ function defineAuthClient(opts) {
49
+ const { config, baseURL, plugins: pluginOpts } = opts;
50
+ const plugins = [];
51
+ if (config.plugins?.admin) plugins.push(adminClient({
52
+ ac: config.plugins.admin.ac,
53
+ roles: config.plugins.admin.roles
54
+ }));
55
+ if (config.plugins?.apiKey) plugins.push(apiKeyClient());
56
+ if (config.plugins?.twoFactor) plugins.push(twoFactorClient({ onTwoFactorRedirect: pluginOpts?.twoFactor?.onTwoFactorRedirect }));
57
+ if (config.methods?.passkey) plugins.push(passkeyClient());
58
+ if (config.methods?.magicLink) plugins.push(magicLinkClient());
59
+ if (config.methods?.phoneOtp) plugins.push(phoneNumberClient());
60
+ if (config.methods?.emailOtp) plugins.push(emailOTPClient());
61
+ if (config.plugins?.username) plugins.push(usernameClient());
62
+ if (config.plugins?.anonymous) plugins.push(anonymousClient());
63
+ if (config.plugins?.multiSession) plugins.push(multiSessionClient());
64
+ if (config.plugins?.sso) plugins.push(ssoClient({ domainVerification: config.plugins.sso.domainVerification ? { enabled: true } : void 0 }));
65
+ return {
66
+ client: createAuthClient({
67
+ baseURL: (baseURL ?? config.baseURL ?? AUTH_BASE_URL) || void 0,
68
+ plugins
69
+ }),
70
+ features: defineAuthFeatures(config)
71
+ };
72
+ }
73
+
74
+ //#endregion
75
+ export { AUTH_BASE_PATH, AUTH_BASE_URL, defineAuthClient, defineAuthFeatures };
@@ -1 +1,45 @@
1
- import e from"i18next";import{initReactI18next as t}from"react-i18next";import n from"i18next-browser-languagedetector";import r from"i18next-http-backend";const i={fallbackLng:`en`,supportedLngs:[`en`],defaultNS:`translation`,ns:[`translation`],interpolation:{escapeValue:!1},react:{useSuspense:!1}};async function a(i){let{loadPath:a=`/locales/{{lng}}/{{ns}}.json`,...o}=i,s=e.use(r).use(n).use(t);if(import.meta.env.MODE!==`production`){let{HMRPlugin:e}=await import(`i18next-hmr/plugin`);s.use(new e({vite:{client:!0}}))}return await s.init({...o,react:{bindI18n:`loaded languageChanged`,bindI18nStore:`added`,useSuspense:!0},backend:{loadPath:a}}),s}export{i as defaultI18nOptions,a as defineI18nClient};
1
+ import i18n from "i18next";
2
+ import { initReactI18next } from "react-i18next";
3
+ import LanguageDetector from "i18next-browser-languagedetector";
4
+ import HttpBackend from "i18next-http-backend";
5
+
6
+ //#region src/web/i18n.ts
7
+ /**
8
+ * Type-safe default options for i18n.
9
+ * Apps should spread these and override as needed.
10
+ */
11
+ const defaultI18nOptions = {
12
+ fallbackLng: "en",
13
+ supportedLngs: ["en"],
14
+ defaultNS: "translation",
15
+ ns: ["translation"],
16
+ interpolation: { escapeValue: false },
17
+ react: { useSuspense: false }
18
+ };
19
+ /**
20
+ * Initializes i18next for browser/SPA with HTTP backend.
21
+ *
22
+ * @param opts - Client i18n options including loadPath for translation files.
23
+ * @returns A promise that resolves to the initialized i18next instance.
24
+ */
25
+ async function defineI18nClient(opts) {
26
+ const { loadPath = "/locales/{{lng}}/{{ns}}.json", ...initOpts } = opts;
27
+ const instance = i18n.use(HttpBackend).use(LanguageDetector).use(initReactI18next);
28
+ if (import.meta.env.MODE !== "production") {
29
+ const { HMRPlugin } = await import("i18next-hmr/plugin");
30
+ instance.use(new HMRPlugin({ vite: { client: true } }));
31
+ }
32
+ await instance.init({
33
+ ...initOpts,
34
+ react: {
35
+ bindI18n: "loaded languageChanged",
36
+ bindI18nStore: "added",
37
+ useSuspense: true
38
+ },
39
+ backend: { loadPath }
40
+ });
41
+ return instance;
42
+ }
43
+
44
+ //#endregion
45
+ export { defaultI18nOptions, defineI18nClient };
@@ -1 +1,8 @@
1
- import{AUTH_BASE_PATH as e,AUTH_BASE_URL as t,defineAuthClient as n,defineAuthFeatures as r}from"./auth.js";import{defaultI18nOptions as i,defineI18nClient as a}from"./i18n.js";import{QueryClient as o,QueryClientProvider as s,useMutation as c,useQuery as l,useQueryClient as u}from"@tanstack/react-query";import{I18nextProvider as d,Trans as f,useTranslation as p}from"react-i18next";export*from"i18next";export{e as AUTH_BASE_PATH,t as AUTH_BASE_URL,d as I18nextProvider,o as QueryClient,s as QueryClientProvider,f as Trans,i as defaultI18nOptions,n as defineAuthClient,r as defineAuthFeatures,a as defineI18nClient,c as useMutation,l as useQuery,u as useQueryClient,p as useTranslation};
1
+ import { AUTH_BASE_PATH, AUTH_BASE_URL, defineAuthClient, defineAuthFeatures } from "./auth.js";
2
+ import { defaultI18nOptions, defineI18nClient } from "./i18n.js";
3
+ import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
+ import { I18nextProvider, Trans, useTranslation } from "react-i18next";
5
+
6
+ export * from "i18next"
7
+
8
+ export { AUTH_BASE_PATH, AUTH_BASE_URL, I18nextProvider, QueryClient, QueryClientProvider, Trans, defaultI18nOptions, defineAuthClient, defineAuthFeatures, defineI18nClient, useMutation, useQuery, useQueryClient, useTranslation };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appos",
3
- "version": "0.3.2-0",
3
+ "version": "0.3.3-0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "release": "release-it",
@@ -129,17 +129,7 @@
129
129
  "dependencies": {
130
130
  "@aws-sdk/client-s3": "^3.955.0",
131
131
  "@aws-sdk/s3-request-presigner": "^3.955.0",
132
- "@better-auth/passkey": "^1.4.7",
133
- "@better-auth/sso": "^1.4.7",
134
- "@clack/prompts": "^0.11.0",
135
132
  "@dbos-inc/dbos-sdk": "^4.5.13",
136
- "@dnd-kit/core": "^6.3.1",
137
- "@dnd-kit/modifiers": "^9.0.0",
138
- "@dnd-kit/sortable": "^10.0.0",
139
- "@dnd-kit/utilities": "^3.2.2",
140
- "@hookform/resolvers": "^5.2.2",
141
- "@keyv/redis": "^5.1.5",
142
- "@marsidev/react-turnstile": "^1.4.0",
143
133
  "@napi-rs/canvas": "^0.1.84",
144
134
  "@opentelemetry/api": "^1.9.0",
145
135
  "@opentelemetry/auto-instrumentations-node": "^0.67.3",
@@ -150,6 +140,23 @@
150
140
  "@opentelemetry/sdk-node": "^0.208.0",
151
141
  "@opentelemetry/sdk-trace-node": "^2.2.0",
152
142
  "@opentelemetry/semantic-conventions": "^1.38.0",
143
+ "canvas": "^3.2.0",
144
+ "sharp": "^0.34.5",
145
+ "pino": "^10.1.0",
146
+ "pino-pretty": "^13.1.3",
147
+ "ultimate-express": "^2.0.13"
148
+ },
149
+ "devDependencies": {
150
+ "@better-auth/passkey": "^1.4.7",
151
+ "@better-auth/sso": "^1.4.7",
152
+ "@clack/prompts": "^0.11.0",
153
+ "@dnd-kit/core": "^6.3.1",
154
+ "@dnd-kit/modifiers": "^9.0.0",
155
+ "@dnd-kit/sortable": "^10.0.0",
156
+ "@dnd-kit/utilities": "^3.2.2",
157
+ "@hookform/resolvers": "^5.2.2",
158
+ "@keyv/redis": "^5.1.5",
159
+ "@marsidev/react-turnstile": "^1.4.0",
153
160
  "@react-email/components": "^1.0.2",
154
161
  "@react-email/render": "^2.0.0",
155
162
  "@react-router/remix-routes-option-adapter": "^7.11.0",
@@ -180,7 +187,6 @@
180
187
  "@types/supertest": "^6.0.3",
181
188
  "@vitejs/plugin-react": "^5.1.2",
182
189
  "better-auth": "^1.4.7",
183
- "canvas": "^3.2.0",
184
190
  "class-variance-authority": "^0.7.1",
185
191
  "clsx": "^2.1.1",
186
192
  "cmdk": "^1.1.1",
@@ -215,8 +221,6 @@
215
221
  "pdfjs-dist": "^5.4.449",
216
222
  "pg": "^8.16.3",
217
223
  "picocolors": "^1.1.1",
218
- "pino": "^10.1.0",
219
- "pino-pretty": "^13.1.3",
220
224
  "radix-ui": "^1.4.3",
221
225
  "rate-limit-redis": "^4.3.1",
222
226
  "react": "^19.2.3",
@@ -229,7 +233,6 @@
229
233
  "redis": "^5.10.0",
230
234
  "release-it": "^19.1.0",
231
235
  "remix-flat-routes": "^0.8.5",
232
- "sharp": "^0.34.5",
233
236
  "sonner": "^2.0.7",
234
237
  "superjson": "^2.2.6",
235
238
  "supertest": "^7.1.4",
@@ -237,14 +240,13 @@
237
240
  "tailwindcss": "^4.1.18",
238
241
  "tsx": "^4.21.0",
239
242
  "tw-animate-css": "^1.4.0",
240
- "ultimate-express": "^2.0.13",
241
243
  "vaul": "^1.1.2",
242
244
  "vite": "^8.0.0-beta.3",
243
245
  "vite-plugin-babel": "^1.3.2",
244
246
  "vite-tsconfig-paths": "^6.0.3",
245
247
  "vitest": "^4.0.16",
246
248
  "vitest-mock-extended": "^3.1.0",
247
- "youch": "^3.3.4",
249
+ "youch": "^4.1.0-beta.13",
248
250
  "zod": "^4.2.1",
249
251
  "zod-openapi": "^5.4.5"
250
252
  },
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{sql as e}from"drizzle-orm";import{pgTable as t}from"drizzle-orm/pg-core";function n(){let n=t(`accounts`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),accessToken:t.text(`access_token`),accessTokenExpiresAt:t.timestamp(`access_token_expires_at`,{mode:`string`,withTimezone:!0}),accountId:t.text(`account_id`).notNull(),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),idToken:t.text(`id_token`),providerId:t.text(`provider_id`).notNull(),password:t.text(`password`),userId:t.text(`user_id`).notNull().references(()=>l.id,{onDelete:`cascade`}),refreshToken:t.text(`refresh_token`),refreshTokenExpiresAt:t.timestamp(`refresh_token_expires_at`,{mode:`string`,withTimezone:!0}),scope:t.text(`scope`),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),r=t(`api_keys`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),name:t.text(`name`),enabled:t.boolean(`enabled`).default(!0),expiresAt:t.timestamp(`expires_at`,{mode:`string`,withTimezone:!0}),key:t.text(`key`).notNull(),lastRefillAt:t.timestamp(`last_refill_at`,{mode:`string`,withTimezone:!0}),lastRequest:t.timestamp(`last_request`,{mode:`string`,withTimezone:!0}),lastUsedAt:t.timestamp(`last_used_at`,{mode:`string`,withTimezone:!0}),metadata:t.text(`metadata`),permissions:t.text(`permissions`),prefix:t.text(`prefix`),rateLimitEnabled:t.boolean(`rate_limit_enabled`).default(!0),rateLimitTimeWindow:t.integer(`rate_limit_time_window`).default(864e5),rateLimitMax:t.integer(`rate_limit_max`).default(10),refillInterval:t.integer(`refill_interval`),refillAmount:t.integer(`refill_amount`),requestCount:t.integer(`request_count`),remaining:t.integer(`remaining`),start:t.text(`start`),userId:t.text(`user_id`).notNull().references(()=>l.id,{onDelete:`cascade`}),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),i=t(`invitations`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),email:t.text(`email`).notNull(),expiresAt:t.timestamp(`expires_at`,{mode:`string`,withTimezone:!0}).notNull(),inviterId:t.text(`inviter_id`).notNull().references(()=>l.id,{onDelete:`cascade`}),organizationId:t.text(`organization_id`).notNull().references(()=>o.id,{onDelete:`cascade`}),role:t.text(`role`),status:t.text(`status`).default(`pending`).notNull(),teamId:t.text(`team_id`),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),a=t(`members`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),organizationId:t.text(`organization_id`).notNull().references(()=>o.id,{onDelete:`cascade`}),role:t.text(`role`).default(`member`).notNull(),userId:t.text(`user_id`).notNull().references(()=>l.id,{onDelete:`cascade`}),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),o=t(`organizations`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),name:t.text(`name`).notNull(),slug:t.text(`slug`).unique(),logo:t.text(`logo`),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),metadata:t.text(`metadata`)}),e=>[]),s=t(`sessions`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),activeOrganizationId:t.text(`active_organization_id`).references(()=>o.id,{onDelete:`set null`}),activeTeamId:t.text(`active_team_id`),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),expiresAt:t.timestamp(`expires_at`,{mode:`string`,withTimezone:!0}).notNull(),impersonatedBy:t.text(`impersonated_by`).references(()=>l.id,{onDelete:`set null`}),ipAddress:t.text(`ip_address`),token:t.text(`token`).notNull().unique(),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),userAgent:t.text(`user_agent`),userId:t.text(`user_id`).notNull().references(()=>l.id,{onDelete:`cascade`})}),e=>[]),c=t(`sso_providers`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),domain:t.text(`domain`).notNull(),issuer:t.text(`issuer`).notNull(),oidcConfig:t.text(`oidc_config`),organizationId:t.text(`organization_id`).references(()=>o.id,{onDelete:`cascade`}),providerId:t.text(`provider_id`).notNull().unique(),samlConfig:t.text(`saml_config`),userId:t.text(`user_id`).references(()=>l.id,{onDelete:`cascade`})}),e=>[]),l=t(`users`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),banExpires:t.timestamp(`ban_expires`,{mode:`string`,withTimezone:!0}),banReason:t.text(`ban_reason`),banned:t.boolean(`banned`).default(!1),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),displayUsername:t.text(`display_username`),email:t.text(`email`).notNull().unique(),emailVerified:t.boolean(`email_verified`).default(!1).notNull(),image:t.text(`image`),isAnonymous:t.boolean(`is_anonymous`),lastLoginMethod:t.text(`last_login_method`),name:t.text(`name`).notNull(),phoneNumber:t.text(`phone_number`).unique(),phoneNumberVerified:t.boolean(`phone_number_verified`),role:t.text(`role`),twoFactorEnabled:t.boolean(`two_factor_enabled`).default(!1),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),username:t.text(`username`).unique()}),e=>[]),u=t(`teams`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),name:t.text(`name`).notNull(),organizationId:t.text(`organization_id`).notNull().references(()=>o.id,{onDelete:`cascade`}),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),d=t(`team_members`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),teamId:t.text(`team_id`).notNull().references(()=>u.id,{onDelete:`cascade`}),userId:t.text(`user_id`).notNull().references(()=>l.id,{onDelete:`cascade`}),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),f=t(`two_factors`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),secret:t.text(`secret`).notNull(),backupCodes:t.text(`backup_codes`).notNull(),userId:t.text(`user_id`).notNull().references(()=>l.id,{onDelete:`cascade`})}),e=>[]),p=t(`verifications`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),expiresAt:t.timestamp(`expires_at`,{mode:`string`,withTimezone:!0}).notNull(),identifier:t.text(`identifier`).notNull(),updatedAt:t.timestamp(`updated_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull(),value:t.text(`value`).notNull()}),e=>[]);return{tables:{accounts:n,apiKeys:r,auditLogs:t(`audit_logs`,t=>({id:t.text(`id`).primaryKey().default(e`uuidv7()`),tableName:t.text(`table_name`),action:t.text(`action`).notNull(),customAction:t.text(`custom_action`),oldData:t.jsonb(`old_data`),newData:t.jsonb(`new_data`),metadata:t.jsonb(`metadata`),organizationId:t.text(`organization_id`).references(()=>o.id,{onDelete:`set null`}),userId:t.text(`user_id`).references(()=>l.id,{onDelete:`set null`}),sessionId:t.text(`session_id`).references(()=>s.id,{onDelete:`set null`}),requestId:t.text(`request_id`),createdAt:t.timestamp(`created_at`,{mode:`string`,withTimezone:!0}).default(e`NOW()`).notNull()}),e=>[]),invitations:i,members:a,organizations:o,sessions:s,ssoProviders:c,teams:u,teamMembers:d,twoFactors:f,users:l,verifications:p},relations:e=>({users:{sessions:e.many.sessions({from:e.users.id,to:e.sessions.userId}),accounts:e.many.accounts({from:e.users.id,to:e.accounts.userId}),apiKeys:e.many.apiKeys({from:e.users.id,to:e.apiKeys.userId}),memberships:e.many.members({from:e.users.id,to:e.members.userId}),invitations:e.many.invitations({from:e.users.id,to:e.invitations.inviterId}),ssoProvider:e.one.ssoProviders({from:e.users.id,to:e.ssoProviders.userId}),twoFactor:e.one.twoFactors({from:e.users.id,to:e.twoFactors.userId})},sessions:{user:e.one.users({from:e.sessions.userId,to:e.users.id})},accounts:{user:e.one.users({from:e.accounts.userId,to:e.users.id})},apiKeys:{user:e.one.users({from:e.apiKeys.userId,to:e.users.id})},organizations:{members:e.many.members({from:e.organizations.id,to:e.members.organizationId}),invitations:e.many.invitations({from:e.organizations.id,to:e.invitations.organizationId}),teams:e.many.teams({from:e.organizations.id,to:e.teams.organizationId})},members:{organization:e.one.organizations({from:e.members.organizationId,to:e.organizations.id}),user:e.one.users({from:e.members.userId,to:e.users.id})},invitations:{organization:e.one.organizations({from:e.invitations.organizationId,to:e.organizations.id}),inviter:e.one.users({from:e.invitations.inviterId,to:e.users.id})},teams:{organization:e.one.organizations({from:e.teams.organizationId,to:e.organizations.id})},ssoProviders:{user:e.one.users({from:e.ssoProviders.userId,to:e.users.id})},verifications:{},twoFactors:{user:e.one.users({from:e.twoFactors.userId,to:e.users.id})},auditLogs:{organization:e.one.organizations({from:e.auditLogs.organizationId,to:e.organizations.id}),user:e.one.users({from:e.auditLogs.userId,to:e.users.id}),session:e.one.sessions({from:e.auditLogs.sessionId,to:e.sessions.id})}})}}export{n as t};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{c as e,i as t,s as n}from"./workflow-BNUZrj4F.mjs";import{basename as r,join as i}from"node:path";import{glob as a}from"node:fs/promises";import{camelCase as o}from"es-toolkit";import{z as s}from"zod";import{createClient as c}from"redis";function l(e){let t=null,n=null;return{inputSchema:e.input,get name(){return n},register(e,r){t=e,n=r},async emit(r){if(!t||!n)throw Error(`Event not registered. Ensure the worker is started before emitting events.`);let i=e.input.parse(r),a={container:t,input:i};await e.run(a),t.eventBus.publish(n,i).catch(e=>{t.logger.error({err:e,event:n},`Redis publish failed`)})},async subscribe(r){if(!t||!n)throw Error(`Event not registered. Ensure the worker is started before subscribing.`);return t.eventBus.subscribe(n,async i=>{let a=e.input.parse(i),o={container:t,input:a};try{await r(o)}catch(e){t.logger.error({err:e,event:n},`Event subscription handler error`)}})}}}const u=l({input:s.object({action:s.enum([`INSERT`,`UPDATE`,`DELETE`]),newData:s.record(s.string(),s.unknown()).nullable(),oldData:s.record(s.string(),s.unknown()).nullable(),organizationId:s.string().nullable(),tableName:s.string(),timestamp:s.string(),userId:s.string().nullable()}),async run(){}});function d(e){return o(r(e,`.ts`))}async function f(r){let{container:o}=r,s=r.eventsDir??i(process.cwd(),t,n);u.register(o,`dbChanges`);let c=await Array.fromAsync(a(`${s}/**/*.${e}`,{exclude:[`**/*.test.ts`,`**/*.spec.ts`,`**/*.test.js`,`**/*.spec.js`]}));for(let e of c){let t=await import(e);if(t.default&&typeof t.default==`object`&&`emit`in t.default&&`subscribe`in t.default){let n=d(e);t.default.register(o,n)}}}export{f as n,u as t};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{n as e}from"./workflow-BNUZrj4F.mjs";import{join as t}from"node:path";import n from"zod";import{ALL_FORMATS as r,BlobSource as i,Input as a}from"mediabunny";const o=e({input:n.object({blobId:n.string()}),async run({container:e,input:{blobId:n},step:o}){let s=await o(`fetch-blob`,async()=>e.storage.primary.getBlob(n));if(!s)throw Error(`Blob ${n} not found`);let c=await o(`download-blob`,async()=>e.storage.primary.downloadBlob(n));if(!c)throw Error(`Failed to download blob ${n}`);let l={};return s.contentType?.startsWith(`image/`)?l=await o(`extract-image-metadata`,async()=>{let e=(await import(`sharp`)).default,t=await e(c).metadata();return{width:t.width,height:t.height,format:t.format,hasAlpha:t.hasAlpha,space:t.space}}):s.contentType?.startsWith(`video/`)||s.contentType?.startsWith(`audio/`)?l=await o(`extract-media-metadata`,async()=>{let e=new Uint8Array(c),t=new a({source:new i(new Blob([e],{type:s.contentType||`video/mp4`})),formats:r}),n=await t.computeDuration(),o=await t.getMetadataTags(),l={},u={},d=!1,f=!1;try{let e=await t.getPrimaryVideoTrack();if(e){d=!0;let t=e.displayWidth&&e.displayHeight?e.displayWidth/e.displayHeight:null;l={width:e.displayWidth,height:e.displayHeight,rotation:e.rotation,angle:e.rotation,displayAspectRatio:t}}}catch{}try{let e=await t.getPrimaryAudioTrack();e&&(f=!0,u={sampleRate:e.sampleRate,channels:e.numberOfChannels})}catch{}return{duration:n,video:d,audio:f,...l,...u,tags:o}}):s.contentType===`application/pdf`&&(l=await o(`extract-pdf-metadata`,async()=>{try{let e=await import(`pdfjs-dist/legacy/build/pdf.mjs`),n=`${t(process.cwd(),`node_modules/pdfjs-dist/standard_fonts`)}/`,r=await e.getDocument({data:new Uint8Array(c),standardFontDataUrl:n}).promise,i=await r.getMetadata(),a=(await r.getPage(1)).getViewport({scale:1}),o=i.info;return{pageCount:r.numPages,width:a.width,height:a.height,title:o?.Title||null,author:o?.Author||null,subject:o?.Subject||null,keywords:o?.Keywords||null,creator:o?.Creator||null,producer:o?.Producer||null,creationDate:o?.CreationDate||null,modificationDate:o?.ModDate||null,pdfVersion:o?.PDFFormatVersion||null}}catch(t){return e.logger.error({error:t,errorMessage:t instanceof Error?t.message:String(t),errorStack:t instanceof Error?t.stack:void 0,errorCode:t?.code,blobId:n},`Failed to extract PDF metadata`),{error:`Failed to extract PDF metadata`,errorMessage:t instanceof Error?t.message:String(t)}}})),await o(`save-metadata`,async()=>{await e.storage.primary.updateBlobMetadata(n,{...l,analyzed:!0})}),e.logger.info({blobId:n,metadata:l},`Metadata extracted`),{...l,analyzed:!0}}});export{o as extractBlobMetadata};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{n as e}from"./workflow-BNUZrj4F.mjs";import{z as t}from"zod";const n=t.object({width:t.number().optional(),height:t.number().optional(),fit:t.enum([`cover`,`contain`,`fill`,`inside`,`outside`]).optional(),position:t.enum([`top`,`right top`,`right`,`right bottom`,`bottom`,`left bottom`,`left`,`left top`,`centre`]).optional(),kernel:t.enum([`nearest`,`linear`,`cubic`,`mitchell`,`lanczos2`,`lanczos3`]).optional()}),r=t.object({resize:n.optional(),rotate:t.number().optional(),flip:t.boolean().optional(),flop:t.boolean().optional(),sharpen:t.boolean().optional(),blur:t.number().optional(),grayscale:t.boolean().optional(),format:t.enum([`jpeg`,`png`,`webp`,`avif`,`gif`]).optional(),quality:t.number().min(1).max(100).optional(),preview:t.literal(!0).optional()}),i=e({input:t.object({blobId:t.string(),transformations:r}),async run({container:e,input:{blobId:t,transformations:n},step:r}){if(!await r(`fetch-blob`,async()=>e.storage.primary.getBlob(t)))throw Error(`Blob ${t} not found`);let i=await r(`download-blob`,async()=>e.storage.primary.downloadBlob(t));if(!i)throw Error(`Failed to download blob ${t}`);let a=await r(`apply-transformations`,async()=>{let e=(await import(`sharp`)).default,t=e(i);return n.resize&&(t=t.resize({width:n.resize.width,height:n.resize.height,fit:n.resize.fit,position:n.resize.position,kernel:n.resize.kernel})),n.rotate!==void 0&&(t=t.rotate(n.rotate)),n.flip&&(t=t.flip()),n.flop&&(t=t.flop()),n.sharpen&&(t=t.sharpen()),n.blur!==void 0&&(t=t.blur(n.blur)),n.grayscale&&(t=t.grayscale()),n.format&&(t=t.toFormat(n.format,{quality:n.quality})),t.toBuffer()}),o=await r(`store-variant`,async()=>e.storage.primary.createVariant(t,n,a));return e.logger.info({blobId:t,variantId:o.id},`Image variant generated`),o}});export{i as generateImageVariant};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{n as e}from"./workflow-BNUZrj4F.mjs";import{spawn as t}from"node:child_process";import{join as n}from"node:path";import r from"zod";const i=e({input:r.object({blobId:r.string(),timeInSeconds:r.number().optional()}),async run({container:e,input:{blobId:r,timeInSeconds:i=1},step:a}){let o=await a(`fetch-blob`,async()=>e.storage.primary.getBlob(r));if(!o)throw Error(`Blob ${r} not found`);let s=await a(`download-blob`,async()=>e.storage.primary.downloadBlob(r));if(!s)throw Error(`Failed to download blob ${r}`);let c=null;if(o.contentType?.startsWith(`video/`))c=await a(`generate-video-preview`,async()=>new Promise((n,a)=>{try{let o=t(`ffmpeg`,[`-i`,`pipe:0`,`-ss`,i.toString(),`-frames:v`,`1`,`-f`,`image2pipe`,`-c:v`,`png`,`pipe:1`]),c=[],l=[];o.stdout.on(`data`,e=>{c.push(e)}),o.stderr.on(`data`,e=>{l.push(e)}),o.on(`close`,async t=>{if(t===0)try{let e=Buffer.concat(c),t=(await import(`sharp`)).default;n(await t(e).jpeg({quality:80}).toBuffer())}catch(t){e.logger.error({error:t,blobId:r},`Failed to convert video frame to JPEG`),a(t)}else{let n=Buffer.concat(l).toString(),i=Error(`FFmpeg exited with code ${t}: ${n}`);e.logger.error({error:i,blobId:r,code:t,stderr:n},`Failed to generate video preview`),a(i)}}),o.on(`error`,t=>{e.logger.error({error:t,blobId:r},`Failed to spawn FFmpeg process`),a(t)}),o.stdin.on(`error`,t=>{t.code!==`EPIPE`&&e.logger.error({error:t,blobId:r},`Failed to write to FFmpeg stdin`)}),o.stdin.write(s),o.stdin.end()}catch(t){e.logger.error({error:t,blobId:r},`Failed to generate video preview`),a(t)}}));else if(o.contentType===`application/pdf`)c=await a(`generate-pdf-preview`,async()=>{try{let e=await import(`pdfjs-dist/legacy/build/pdf.mjs`),{createCanvas:t}=await import(`canvas`),r=(await import(`sharp`)).default,i=`${n(process.cwd(),`node_modules/pdfjs-dist/standard_fonts`)}/`,a=await(await e.getDocument({data:new Uint8Array(s),standardFontDataUrl:i}).promise).getPage(1),o=a.getViewport({scale:2}),c=t(o.width,o.height),l=c.getContext(`2d`);return await a.render({canvasContext:l,viewport:o,canvas:c}).promise,await r(c.toBuffer(`image/png`)).resize(800,800,{fit:`inside`,withoutEnlargement:!0}).jpeg({quality:85}).toBuffer()}catch(t){throw e.logger.error({error:t,errorMessage:t instanceof Error?t.message:String(t),errorStack:t instanceof Error?t.stack:void 0,errorCode:t?.code,blobId:r},`Failed to generate PDF preview`),t}});else if(o.contentType?.startsWith(`image/`))c=await a(`generate-image-preview`,async()=>{let e=(await import(`sharp`)).default;return await e(s).resize(800,800,{fit:`inside`,withoutEnlargement:!0}).jpeg({quality:85}).toBuffer()});else throw Error(`Preview generation not supported for content type: ${o.contentType}`);let l=await a(`store-preview`,async()=>await e.storage.primary.createVariant(r,{preview:!0},c));return e.logger.info({blobId:r,previewId:l.id,contentType:o.contentType},`Preview generated`),l}});export{i as generatePreview};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{n as e}from"./workflow-BNUZrj4F.mjs";import t from"zod";const n=e({input:t.object({attachmentIds:t.array(t.string()).min(1)}),async run({container:e,input:{attachmentIds:t},step:n}){let r=await n(`fetch-attachments`,async()=>(await e.storage.primary.getAttachmentsByIds(t)).filter(e=>e.blob!==null).map(e=>({attachmentId:e.id,blobId:e.blob.id})));return await n(`delete-attachments`,async()=>{for(let{attachmentId:t}of r)await e.storage.primary.deleteAttachment(t)}),await n(`delete-blobs`,async()=>{for(let{blobId:t}of r)await e.storage.primary.deleteBlob(t)}),e.logger.info({attachmentIds:t,blobCount:r.length},`Attachments and blobs purged`),{purgedCount:r.length}}});export{n as purgeAttachment};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{t as e}from"./workflow-BNUZrj4F.mjs";import{t}from"./auth-schema-Va0CYicu.mjs";import{lt as n}from"drizzle-orm";const r=t();function i(t=`0 0 * * *`){return e({crontab:t,async run({container:e,step:t,scheduledTime:i}){let a=e.auth.auditLog?.retentionDays??90,o=new Date(i);o.setDate(o.getDate()-a);let s=o.toISOString(),c=await t(`delete-old-logs`,async()=>{let{auditLogs:t}=r.tables;return(await e.db.primary.delete(t).where(n(t.createdAt,s)).returning({id:t.id})).length});e.logger.info({deletedCount:c,retentionDays:a,cutoffDate:s},`Audit log purge completed`)}})}export{i as definePurgeAuditLogs};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{t as e}from"./event-8JibGFH_.mjs";import{n as t}from"./workflow-BNUZrj4F.mjs";import{t as n}from"./auth-schema-Va0CYicu.mjs";import{z as r}from"zod";const i=n(),a=r.object({changes:r.array(r.object({_table:r.string(),old:r.record(r.string(),r.unknown()).nullable(),new:r.record(r.string(),r.unknown()).nullable()})),dbName:r.string(),organizationId:r.string().nullable(),requestId:r.string(),sessionId:r.string().nullable(),userId:r.string().nullable()});function o(e){return e.old===null?`INSERT`:e.new===null?`DELETE`:`UPDATE`}const s=t({input:a,async run({container:t,step:n,input:r}){let{dbName:a,changes:s,organizationId:c,userId:l,sessionId:u,requestId:d}=r;if(s.length===0)return{processed:0,audited:0,published:0};let f=new Date().toISOString(),p=0,m=0;for(let r of s){let s=r._table,h=o(r),g=`${a}.${s}`;t.auth.shouldAudit(g)&&(await n(`audit:${g}`,async()=>{await t.db.primary.insert(i.tables.auditLogs).values({tableName:g,action:h,oldData:r.old,newData:r.new,organizationId:c,userId:l,sessionId:u,requestId:d,createdAt:f})}),p++),await n(`event:${g}`,async()=>{await e.emit({action:h,oldData:r.old,newData:r.new,organizationId:c,tableName:g,timestamp:f,userId:l})}),m++}return{processed:s.length,audited:p,published:m}}});export{s as trackDbChanges};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import{basename as e,join as t}from"node:path";import{glob as n}from"node:fs/promises";import{camelCase as r}from"es-toolkit";const i=`api`,a=`databases`,o=`routes`,s=`events`,c=`commands`,l=`public`,u=process.env.NODE_ENV===`production`?`js`:`ts`;function d(e){let t=null,n=null,r=null,i=null,a=async i=>{if(!t||!r)throw Error(`Workflow "${n}" not registered`);let a=r,o=a.workflowID;if(!o)throw Error(`DBOS.workflowID is not available in this context`);let s={container:t,workflowId:o,input:i,step:(e,t)=>a.runStep(t,{name:e})};return e.run(s)};return{inputSchema:e.input,get name(){return n},register(o,s,c){t=o,n=s,r=c,i=c.registerWorkflow(a,{name:s,...e.config})},async start(t){if(!i||!n||!r)throw Error(`Workflow not registered. Ensure the worker is started before triggering workflows.`);let a=e.input.parse(t),o=await r.startWorkflow(i)(a);return{workflowId:o.workflowID,getStatus:()=>o.getStatus(),getResult:()=>o.getResult()}}}}function f(e){let t=null,n=null,r=null,i=async(i,a)=>{if(!t||!r)throw Error(`Workflow "${n}" not registered`);let o=r,s=o.workflowID;if(!s)throw Error(`DBOS.workflowID is not available in this context`);let c={container:t,workflowId:s,scheduledTime:i,step:(e,t)=>o.runStep(t,{name:e})};return e.run(c)};return{crontab:e.crontab,get name(){return n},register(a,o,s){t=a,n=o,r=s,s.registerScheduled(s.registerWorkflow(i,{name:o}),{crontab:e.crontab})}}}function p(t){return r(e(t,`.ts`))}async function m(e){let{container:r,dbos:i}=e,a=e.workflowsDir??t(process.cwd(),`api`,`workflows`),o=(e,t)=>{try{e.register(r,t,i)}catch(e){if(!(e instanceof Error)||!e.message.includes(`already registered`))throw e}},{extractBlobMetadata:s}=await import(`./extract-blob-metadata-DjPfHtQ2.mjs`),{generateImageVariant:c}=await import(`./generate-image-variant-D5VDFyWj.mjs`),{generatePreview:l}=await import(`./generate-preview-Dssw7w5U.mjs`),{purgeAttachment:d}=await import(`./purge-attachment-BBPzIxwt.mjs`),{trackDbChanges:f}=await import(`./track-db-changes-CFykw_YO.mjs`),{definePurgeAuditLogs:m}=await import(`./purge-audit-logs-BeZy3IFM.mjs`),{definePurgeUnattachedBlobs:h}=await import(`./purge-unattached-blobs-Duvv8Izd.mjs`);o(s,`extractBlobMetadata`),o(c,`generateImageVariant`),o(l,`generatePreview`),o(d,`purgeAttachment`),o(f,`trackDbChanges`),o(m(r.auth.auditLog?.purgeCron),`purgeAuditLogs`),o(h(r.storage.primary.purgeCron),`purgeUnattachedBlobs`);let g=await Array.fromAsync(n(`${a}/**/*.${u}`,{exclude:[`**/*.test.ts`,`**/*.spec.ts`,`**/*.test.js`,`**/*.spec.js`]}));for(let e of g){let t=await import(e);if(t.default&&typeof t.default==`object`&&`register`in t.default){let n=p(e);o(t.default,n)}}}export{c as a,u as c,i,l,d as n,a as o,m as r,s,f as t,o as u};
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- function e(e){if(e&&typeof e==`object`&&`status`in e){let t=e.status;if(typeof t==`number`)return t}return e instanceof SyntaxError?400:500}function t(t,n={}){return async(r,i,a,o)=>{if(process.env.NODE_ENV===`production`)return o(r);try{let{default:t}=await import(`youch`),o=new t(r,i);o.addLink(e=>`<a href="${`https://stackoverflow.com/search?q=${encodeURIComponent(e)}`}" target="_blank" title="Search on StackOverflow">Search Stack Overflow</a>`),o.addLink(e=>`<a href="${`https://www.google.com/search?q=${encodeURIComponent(e)}`}" target="_blank" title="Search on Google">Search Google</a>`);let s=await o.toHTML().then(e=>n.theme===`dark`?e.replace(`<style>`,`<style>body { background: #1a1a1a; color: #f0f0f0; }`):e);a.writeHead(e(r),{"content-type":`text/html`}),a.end(s)}catch(n){t.error({error:n instanceof Error?n.message:n,originalError:r instanceof Error?r.message:r},`Failed to render Youch error page`),a.status(e(r)).json({error:{message:r instanceof Error?r.message:`Internal server error`,...process.env.NODE_ENV!==`production`&&{stack:r instanceof Error?r.stack:void 0}}})}}}export{t as defineYouchErrorHandler};