appos 0.3.2-0 → 0.3.4-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 (158) 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/api/storage.d.mts +4 -4
  140. package/dist/exports/tests/constants.mjs +1 -1
  141. package/dist/exports/vendors/date.js +1 -1
  142. package/dist/exports/vendors/toolkit.js +1 -1
  143. package/dist/exports/vendors/zod.js +1 -1
  144. package/dist/exports/vitest/globals.mjs +1 -1
  145. package/dist/exports/web/auth.js +75 -1
  146. package/dist/exports/web/i18n.js +45 -1
  147. package/dist/exports/web/index.js +8 -1
  148. package/package.json +19 -18
  149. package/dist/bin/auth-schema-Va0CYicu.mjs +0 -2
  150. package/dist/bin/event-8JibGFH_.mjs +0 -2
  151. package/dist/bin/extract-blob-metadata-DjPfHtQ2.mjs +0 -2
  152. package/dist/bin/generate-image-variant-D5VDFyWj.mjs +0 -2
  153. package/dist/bin/generate-preview-Dssw7w5U.mjs +0 -2
  154. package/dist/bin/purge-attachment-BBPzIxwt.mjs +0 -2
  155. package/dist/bin/purge-audit-logs-BeZy3IFM.mjs +0 -2
  156. package/dist/bin/track-db-changes-CFykw_YO.mjs +0 -2
  157. package/dist/bin/workflow-BNUZrj4F.mjs +0 -2
  158. 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};
@@ -239,14 +239,14 @@ declare class StorageService<TDiskNames extends string = string, TTableNames ext
239
239
  blobId: string;
240
240
  blob: {
241
241
  id: string;
242
- createdAt: string;
243
242
  key: string;
244
- metadata: unknown;
245
243
  filename: string;
246
244
  contentType: string | null;
245
+ metadata: unknown;
247
246
  serviceName: string;
248
247
  byteSize: number;
249
248
  checksum: string | null;
249
+ createdAt: string;
250
250
  } | null;
251
251
  }[]>;
252
252
  /**
@@ -263,14 +263,14 @@ declare class StorageService<TDiskNames extends string = string, TTableNames ext
263
263
  blobId: string;
264
264
  blob: {
265
265
  id: string;
266
- createdAt: string;
267
266
  key: string;
268
- metadata: unknown;
269
267
  filename: string;
270
268
  contentType: string | null;
269
+ metadata: unknown;
271
270
  serviceName: string;
272
271
  byteSize: number;
273
272
  checksum: string | null;
273
+ createdAt: string;
274
274
  } | null;
275
275
  }[]>;
276
276
  /**
@@ -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.4-0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "release": "release-it",
@@ -129,18 +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
- "@napi-rs/canvas": "^0.1.84",
144
133
  "@opentelemetry/api": "^1.9.0",
145
134
  "@opentelemetry/auto-instrumentations-node": "^0.67.3",
146
135
  "@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
@@ -150,6 +139,23 @@
150
139
  "@opentelemetry/sdk-node": "^0.208.0",
151
140
  "@opentelemetry/sdk-trace-node": "^2.2.0",
152
141
  "@opentelemetry/semantic-conventions": "^1.38.0",
142
+ "canvas": "^3.2.0",
143
+ "sharp": "^0.34.5",
144
+ "pino": "^10.1.0",
145
+ "pino-pretty": "^13.1.3",
146
+ "ultimate-express": "^2.0.13"
147
+ },
148
+ "devDependencies": {
149
+ "@better-auth/passkey": "^1.4.7",
150
+ "@better-auth/sso": "^1.4.7",
151
+ "@clack/prompts": "^0.11.0",
152
+ "@dnd-kit/core": "^6.3.1",
153
+ "@dnd-kit/modifiers": "^9.0.0",
154
+ "@dnd-kit/sortable": "^10.0.0",
155
+ "@dnd-kit/utilities": "^3.2.2",
156
+ "@hookform/resolvers": "^5.2.2",
157
+ "@keyv/redis": "^5.1.5",
158
+ "@marsidev/react-turnstile": "^1.4.0",
153
159
  "@react-email/components": "^1.0.2",
154
160
  "@react-email/render": "^2.0.0",
155
161
  "@react-router/remix-routes-option-adapter": "^7.11.0",
@@ -180,7 +186,6 @@
180
186
  "@types/supertest": "^6.0.3",
181
187
  "@vitejs/plugin-react": "^5.1.2",
182
188
  "better-auth": "^1.4.7",
183
- "canvas": "^3.2.0",
184
189
  "class-variance-authority": "^0.7.1",
185
190
  "clsx": "^2.1.1",
186
191
  "cmdk": "^1.1.1",
@@ -215,8 +220,6 @@
215
220
  "pdfjs-dist": "^5.4.449",
216
221
  "pg": "^8.16.3",
217
222
  "picocolors": "^1.1.1",
218
- "pino": "^10.1.0",
219
- "pino-pretty": "^13.1.3",
220
223
  "radix-ui": "^1.4.3",
221
224
  "rate-limit-redis": "^4.3.1",
222
225
  "react": "^19.2.3",
@@ -229,7 +232,6 @@
229
232
  "redis": "^5.10.0",
230
233
  "release-it": "^19.1.0",
231
234
  "remix-flat-routes": "^0.8.5",
232
- "sharp": "^0.34.5",
233
235
  "sonner": "^2.0.7",
234
236
  "superjson": "^2.2.6",
235
237
  "supertest": "^7.1.4",
@@ -237,14 +239,13 @@
237
239
  "tailwindcss": "^4.1.18",
238
240
  "tsx": "^4.21.0",
239
241
  "tw-animate-css": "^1.4.0",
240
- "ultimate-express": "^2.0.13",
241
242
  "vaul": "^1.1.2",
242
243
  "vite": "^8.0.0-beta.3",
243
244
  "vite-plugin-babel": "^1.3.2",
244
245
  "vite-tsconfig-paths": "^6.0.3",
245
246
  "vitest": "^4.0.16",
246
247
  "vitest-mock-extended": "^3.1.0",
247
- "youch": "^3.3.4",
248
+ "youch": "^4.1.0-beta.13",
248
249
  "zod": "^4.2.1",
249
250
  "zod-openapi": "^5.4.5"
250
251
  },
@@ -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};