alepha 0.18.2 → 0.18.3
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.
- package/assets/devtools-ui/200.html +2 -2
- package/assets/devtools-ui/200.html.br +0 -0
- package/assets/devtools-ui/404.html +2 -2
- package/assets/devtools-ui/404.html.br +0 -0
- package/assets/devtools-ui/{asset.BfSBZ5Dd.css → asset.hG_f8HuK.css} +1 -1
- package/assets/devtools-ui/asset.hG_f8HuK.css.br +0 -0
- package/assets/devtools-ui/chunk.B3au4Lhg.js +1 -0
- package/assets/devtools-ui/chunk.B3au4Lhg.js.br +0 -0
- package/assets/devtools-ui/chunk.BLOrlnMB.js +1 -0
- package/assets/devtools-ui/chunk.BLOrlnMB.js.br +0 -0
- package/assets/devtools-ui/chunk.BLR01ljW.js +1 -0
- package/assets/devtools-ui/chunk.BLR01ljW.js.br +0 -0
- package/assets/devtools-ui/chunk.BTXaIUlA.js +1 -0
- package/assets/devtools-ui/chunk.BTXaIUlA.js.br +0 -0
- package/assets/devtools-ui/{chunk.lJL-lgnW.js → chunk.BhJaxmm8.js} +1 -1
- package/assets/devtools-ui/chunk.BhJaxmm8.js.br +0 -0
- package/assets/devtools-ui/chunk.BtoNxFuL.js +1 -0
- package/assets/devtools-ui/chunk.BtoNxFuL.js.br +0 -0
- package/assets/devtools-ui/chunk.C8YUV2Wd.js +1 -0
- package/assets/devtools-ui/chunk.C8YUV2Wd.js.br +0 -0
- package/assets/devtools-ui/{chunk.M6wyKO_3.js → chunk.CBbIgDzE.js} +2 -2
- package/assets/devtools-ui/chunk.CBbIgDzE.js.br +0 -0
- package/assets/devtools-ui/chunk.CFqIniwA.js +1 -0
- package/assets/devtools-ui/chunk.CFqIniwA.js.br +0 -0
- package/assets/devtools-ui/chunk.CLFF7f7-.js +1 -0
- package/assets/devtools-ui/chunk.CLFF7f7-.js.br +0 -0
- package/assets/devtools-ui/chunk.CRsBbA10.js +1 -0
- package/assets/devtools-ui/chunk.CRsBbA10.js.br +0 -0
- package/assets/devtools-ui/{chunk.DbEH1oOB.js → chunk.CZPo6v95.js} +1 -1
- package/assets/devtools-ui/chunk.CZPo6v95.js.br +0 -0
- package/assets/devtools-ui/chunk.D0fWgNos.js +1 -0
- package/assets/devtools-ui/chunk.D0fWgNos.js.br +1 -0
- package/assets/devtools-ui/chunk.D7-0ziQ6.js +1 -0
- package/assets/devtools-ui/chunk.D7-0ziQ6.js.br +0 -0
- package/assets/devtools-ui/chunk.DAewe0vm.js +1 -0
- package/assets/devtools-ui/chunk.DAewe0vm.js.br +0 -0
- package/assets/devtools-ui/chunk.DJRQEYqK.js +1 -0
- package/assets/devtools-ui/chunk.DJRQEYqK.js.br +0 -0
- package/assets/devtools-ui/{chunk.CZl6J9DF.js → chunk.DMAxv14p.js} +1 -1
- package/assets/devtools-ui/chunk.DMAxv14p.js.br +0 -0
- package/assets/devtools-ui/{chunk.BT2IiBkZ.js → chunk.DMImnNjU.js} +1 -1
- package/assets/devtools-ui/chunk.DMImnNjU.js.br +0 -0
- package/assets/devtools-ui/chunk.DeeQsidk.js +9 -0
- package/assets/devtools-ui/chunk.DeeQsidk.js.br +0 -0
- package/assets/devtools-ui/chunk.DqEwn9Vj.js +7 -0
- package/assets/devtools-ui/chunk.DqEwn9Vj.js.br +0 -0
- package/assets/devtools-ui/chunk.Dt8OsQey.js +1 -0
- package/assets/devtools-ui/chunk.Dt8OsQey.js.br +0 -0
- package/assets/devtools-ui/{chunk.B9pX3zit.js → chunk.Dtp8oa_f.js} +1 -1
- package/assets/devtools-ui/chunk.Dtp8oa_f.js.br +0 -0
- package/assets/devtools-ui/chunk.Dx3JzAYM.js +1 -0
- package/assets/devtools-ui/chunk.Dx3JzAYM.js.br +0 -0
- package/assets/devtools-ui/chunk.GCOj1-5E.js +1 -0
- package/assets/devtools-ui/chunk.GCOj1-5E.js.br +0 -0
- package/assets/devtools-ui/chunk.IC1LD8BH.js +1 -0
- package/assets/devtools-ui/chunk.IC1LD8BH.js.br +0 -0
- package/assets/devtools-ui/chunk.IwuB_TqW.js +1 -0
- package/assets/devtools-ui/chunk.IwuB_TqW.js.br +0 -0
- package/assets/devtools-ui/chunk.Qqapj2zq.js +1 -0
- package/assets/devtools-ui/chunk.Qqapj2zq.js.br +0 -0
- package/assets/devtools-ui/{chunk.C79YouPp.js → chunk.TKKKndOy.js} +1 -1
- package/assets/devtools-ui/chunk.TKKKndOy.js.br +0 -0
- package/assets/devtools-ui/chunk.YHTVhFQT.js +1 -0
- package/assets/devtools-ui/chunk.YHTVhFQT.js.br +0 -0
- package/assets/devtools-ui/chunk.fnod6uEi.js +1 -0
- package/assets/devtools-ui/chunk.fnod6uEi.js.br +0 -0
- package/assets/devtools-ui/chunk.mOCRmXjo.js +1 -0
- package/assets/devtools-ui/chunk.mOCRmXjo.js.br +0 -0
- package/assets/devtools-ui/chunk.qZTNEAK0.js +1 -0
- package/assets/devtools-ui/chunk.qZTNEAK0.js.br +0 -0
- package/assets/devtools-ui/chunk.rc9m0y4-.js +1 -0
- package/assets/devtools-ui/chunk.rc9m0y4-.js.br +0 -0
- package/assets/devtools-ui/entry.Cxc5QLCU.js +80 -0
- package/assets/devtools-ui/entry.Cxc5QLCU.js.br +0 -0
- package/assets/devtools-ui/index.html +2 -2
- package/assets/devtools-ui/index.html.br +0 -0
- package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui.css +1 -1
- package/dist/api/audits/index.d.ts +61 -5
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts +61 -5
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/jobs/index.d.ts +61 -5
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +4 -2
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +5 -5
- package/dist/api/notifications/index.browser.js +44 -1
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +187 -2
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +143 -8
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +61 -5
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/users/index.d.ts +330 -93
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +27 -36
- package/dist/api/users/index.js.map +1 -1
- package/dist/cli/config/index.d.ts +46 -0
- package/dist/cli/config/index.d.ts.map +1 -0
- package/dist/cli/config/index.js +20 -0
- package/dist/cli/config/index.js.map +1 -0
- package/dist/cli/core/index.d.ts +69 -66
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +329 -196
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +302 -63
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +455 -25
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/core/index.browser.js +125 -87
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +62 -53
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +125 -87
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +125 -87
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +125 -87
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.d.ts +18 -1
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.js +29 -3
- package/dist/crypto/index.js.map +1 -1
- package/dist/devtools/index.js +3 -12
- package/dist/devtools/index.js.map +1 -1
- package/dist/logger/index.d.ts +10 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +19 -9
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +57 -1
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +378 -19
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +328 -9
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +384 -21
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +49 -17
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +47 -21
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +52 -17
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/core/index.d.ts +1 -1
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +6 -1
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +28 -18
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +92 -56
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/router/index.browser.js +448 -116
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +102 -40
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +453 -92
- package/dist/react/router/index.js.map +1 -1
- package/dist/security/index.d.ts +3 -11
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +6 -11
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +22 -24
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +102 -82
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +7 -4
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +13 -12
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +288 -4
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +375 -2
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js +10 -71
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +32 -49
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +73 -100
- package/dist/server/links/index.js.map +1 -1
- package/dist/system/index.browser.js +221 -2
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.d.ts +63 -1
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +221 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js +224 -4
- package/dist/system/index.workerd.js.map +1 -1
- package/package.json +10 -5
- package/src/api/jobs/providers/JobProvider.ts +6 -3
- package/src/api/notifications/controllers/AdminNotificationController.ts +83 -0
- package/src/api/notifications/index.browser.ts +3 -0
- package/src/api/notifications/index.ts +14 -2
- package/src/api/notifications/jobs/NotificationJobs.ts +11 -2
- package/src/api/notifications/schemas/notificationDetailResourceSchema.ts +20 -0
- package/src/api/notifications/schemas/notificationQuerySchema.ts +19 -0
- package/src/api/notifications/schemas/notificationResourceSchema.ts +18 -0
- package/src/api/notifications/services/NotificationSenderService.ts +15 -2
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +28 -32
- package/src/api/users/buckets/UserBuckets.ts +1 -1
- package/src/api/users/jobs/UserJobs.ts +1 -1
- package/src/api/users/primitives/$realm.ts +8 -49
- package/src/api/users/providers/RealmProvider.ts +2 -3
- package/src/api/users/services/RegistrationService.spec.ts +7 -7
- package/src/api/users/services/RegistrationService.ts +3 -3
- package/src/api/users/services/SessionService.spec.ts +4 -4
- package/src/api/users/services/SessionService.ts +3 -3
- package/src/cli/{core → config}/defineConfig.ts +14 -20
- package/src/cli/config/index.ts +1 -0
- package/src/cli/core/commands/db.ts +65 -1
- package/src/cli/core/commands/dev.ts +1 -0
- package/src/cli/core/commands/init.ts +2 -192
- package/src/cli/core/index.ts +34 -11
- package/src/cli/core/providers/ViteDevServerProvider.ts +52 -13
- package/src/cli/core/services/PackageManagerUtils.ts +43 -21
- package/src/cli/core/services/ProjectScaffolder.ts +214 -2
- package/src/cli/core/services/ViteUtils.ts +57 -0
- package/src/cli/core/tasks/BuildClientTask.ts +7 -2
- package/src/cli/core/tasks/BuildCloudflareTask.ts +4 -12
- package/src/cli/core/tasks/BuildServerTask.ts +2 -0
- package/src/cli/core/tasks/BuildVercelTask.ts +165 -168
- package/src/cli/core/templates/alephaConfigTs.ts +1 -1
- package/src/cli/core/templates/apiAppSecurityTs.ts +5 -8
- package/src/cli/core/templates/tsconfigJson.ts +6 -1
- package/src/cli/platform/adapters/CloudflareAdapter.spec.ts +1 -1
- package/src/cli/platform/adapters/CloudflareAdapter.ts +30 -29
- package/src/cli/platform/atoms/platformOptions.ts +21 -0
- package/src/cli/platform/commands/SecretsCommand.spec.ts +298 -0
- package/src/cli/platform/commands/SecretsCommand.ts +283 -0
- package/src/cli/platform/commands/platform.ts +12 -0
- package/src/cli/platform/index.ts +14 -28
- package/src/cli/platform/providers/GitHubSecretStore.spec.ts +153 -0
- package/src/cli/platform/providers/GitHubSecretStore.ts +112 -0
- package/src/cli/platform/providers/MemorySecretStore.ts +114 -0
- package/src/cli/platform/providers/SecretStoreProvider.ts +39 -0
- package/src/cli/platform/schemas/cloudflare.ts +2 -0
- package/src/cli/platform/services/CloudflareApi.ts +5 -2
- package/src/cli/platform/services/DockerComposeGenerator.spec.ts +115 -0
- package/src/cli/platform/services/DockerComposeGenerator.ts +46 -1
- package/src/cli/platform/services/SecretFilterService.spec.ts +111 -0
- package/src/cli/platform/services/SecretFilterService.ts +54 -0
- package/src/core/Alepha.ts +94 -25
- package/src/core/__tests__/Alepha-parseEnv.spec.ts +20 -0
- package/src/core/primitives/$memoize.ts +38 -26
- package/src/core/providers/AlsProvider.ts +2 -0
- package/src/core/providers/EventManager.ts +4 -0
- package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +1 -4
- package/src/core/providers/KeylessJsonSchemaCodec.ts +19 -125
- package/src/core/providers/SchemaValidator.spec.ts +36 -0
- package/src/core/providers/SchemaValidator.ts +9 -0
- package/src/crypto/index.ts +6 -1
- package/src/crypto/providers/SecretProvider.ts +36 -0
- package/src/devtools/providers/DevToolsProvider.ts +3 -12
- package/src/logger/index.ts +33 -6
- package/src/logger/providers/PrettyFormatterProvider.ts +5 -3
- package/src/orm/__tests__/orm-next-tests.ts +492 -0
- package/src/orm/__tests__/orm-next.spec.ts +140 -0
- package/src/orm/core/constants/PG_SYMBOLS.ts +17 -0
- package/src/orm/core/index.bun.ts +3 -6
- package/src/orm/core/index.shared-server.ts +2 -0
- package/src/orm/core/index.shared.ts +2 -0
- package/src/orm/core/index.ts +5 -7
- package/src/orm/core/interfaces/AggregateQuery.ts +103 -0
- package/src/orm/core/interfaces/PgQueryWhere.ts +7 -0
- package/src/orm/core/primitives/$entity.ts +8 -0
- package/src/orm/core/primitives/$repository.ts +6 -3
- package/src/orm/core/primitives/$view.ts +88 -0
- package/src/orm/core/providers/DbCacheProvider.ts +66 -0
- package/src/orm/core/providers/DrizzleKitProvider.ts +42 -0
- package/src/orm/core/providers/drivers/BunSqliteProvider.ts +2 -3
- package/src/orm/core/providers/drivers/CloudflareD1Provider.ts +12 -0
- package/src/orm/core/providers/drivers/DatabaseProvider.ts +39 -0
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +2 -3
- package/src/orm/core/schemas/databaseEnvSchema.ts +31 -0
- package/src/orm/core/schemas/insertSchema.ts +13 -3
- package/src/orm/core/schemas/updateSchema.ts +14 -3
- package/src/orm/core/services/ModelBuilder.ts +26 -14
- package/src/orm/core/services/QueryManager.ts +13 -0
- package/src/orm/core/services/Repository.ts +307 -5
- package/src/orm/core/services/SqliteModelBuilder.ts +38 -0
- package/src/orm/postgres/index.bun.ts +4 -7
- package/src/orm/postgres/index.ts +4 -7
- package/src/orm/postgres/providers/BunPostgresProvider.ts +12 -2
- package/src/orm/postgres/providers/NodePostgresProvider.ts +7 -0
- package/src/orm/postgres/providers/PglitePostgresProvider.ts +10 -17
- package/src/orm/postgres/providers/PostgresProvider.ts +7 -36
- package/src/orm/postgres/schemas/postgresEnvSchema.ts +32 -0
- package/src/orm/postgres/services/PostgresModelBuilder.ts +40 -0
- package/src/react/core/components/ErrorBoundary.tsx +5 -2
- package/src/react/form/hooks/useFieldValue.ts +34 -0
- package/src/react/form/hooks/useForm.browser.spec.tsx +94 -9
- package/src/react/form/hooks/useForm.ts +14 -2
- package/src/react/form/hooks/useFormState.ts +10 -10
- package/src/react/form/hooks/useFormValues.ts +29 -0
- package/src/react/form/index.ts +3 -1
- package/src/react/form/services/FormModel.ts +53 -122
- package/src/react/router/components/ErrorViewer.tsx +333 -34
- package/src/react/router/components/NestedView.tsx +10 -3
- package/src/react/router/primitives/$page.browser.spec.tsx +34 -0
- package/src/react/router/primitives/$page.spec.tsx +20 -0
- package/src/react/router/primitives/$page.ts +24 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +14 -2
- package/src/react/router/providers/ReactPageProvider.ts +156 -73
- package/src/react/router/providers/ReactServerProvider.ts +40 -2
- package/src/react/router/providers/ReactServerTemplateProvider.ts +13 -1
- package/src/security/providers/SecurityProvider.ts +5 -27
- package/src/server/auth/primitives/$auth.ts +52 -19
- package/src/server/auth/providers/ServerAuthProvider.ts +145 -139
- package/src/server/cookies/providers/ServerCookiesProvider.ts +12 -24
- package/src/server/core/index.ts +3 -1
- package/src/server/core/primitives/$sse.spec.ts +315 -0
- package/src/server/core/primitives/$sse.ts +715 -0
- package/src/server/links/index.browser.ts +1 -3
- package/src/server/links/index.ts +0 -3
- package/src/server/links/providers/LinkProvider.spec.ts +12 -21
- package/src/server/links/providers/LinkProvider.ts +20 -52
- package/src/server/links/providers/ServerLinksProvider.spec.ts +106 -0
- package/src/server/links/providers/ServerLinksProvider.ts +113 -73
- package/src/server/links/schemas/apiLinksResponseSchema.ts +4 -21
- package/src/server/links/services/BatchCollector.ts +5 -3
- package/src/system/index.browser.ts +1 -0
- package/src/system/index.ts +3 -0
- package/src/system/index.workerd.ts +39 -1
- package/src/system/providers/WorkerdFileSystemProvider.ts +365 -0
- package/assets/devtools-ui/asset.BfSBZ5Dd.css.br +0 -0
- package/assets/devtools-ui/chunk.2NYaoqWt.js +0 -1
- package/assets/devtools-ui/chunk.2NYaoqWt.js.br +0 -0
- package/assets/devtools-ui/chunk.B052Z_xQ.js +0 -1
- package/assets/devtools-ui/chunk.B052Z_xQ.js.br +0 -0
- package/assets/devtools-ui/chunk.B4kVY90C.js +0 -1
- package/assets/devtools-ui/chunk.B4kVY90C.js.br +0 -0
- package/assets/devtools-ui/chunk.B7QJXctB.js +0 -1
- package/assets/devtools-ui/chunk.B7QJXctB.js.br +0 -0
- package/assets/devtools-ui/chunk.B9pX3zit.js.br +0 -0
- package/assets/devtools-ui/chunk.BKF9JxIo.js +0 -1
- package/assets/devtools-ui/chunk.BKF9JxIo.js.br +0 -0
- package/assets/devtools-ui/chunk.BOHgdTP-.js +0 -1
- package/assets/devtools-ui/chunk.BOHgdTP-.js.br +0 -0
- package/assets/devtools-ui/chunk.BOVFxkYC.js +0 -1
- package/assets/devtools-ui/chunk.BOVFxkYC.js.br +0 -0
- package/assets/devtools-ui/chunk.BR842zj5.js +0 -1
- package/assets/devtools-ui/chunk.BR842zj5.js.br +0 -0
- package/assets/devtools-ui/chunk.BT2IiBkZ.js.br +0 -0
- package/assets/devtools-ui/chunk.C79YouPp.js.br +0 -0
- package/assets/devtools-ui/chunk.C8mlBrjW.js +0 -9
- package/assets/devtools-ui/chunk.C8mlBrjW.js.br +0 -0
- package/assets/devtools-ui/chunk.CK0ow3AZ.js +0 -1
- package/assets/devtools-ui/chunk.CK0ow3AZ.js.br +0 -0
- package/assets/devtools-ui/chunk.CZl6J9DF.js.br +0 -0
- package/assets/devtools-ui/chunk.CdNr0YzS.js +0 -1
- package/assets/devtools-ui/chunk.CdNr0YzS.js.br +0 -0
- package/assets/devtools-ui/chunk.Ce6_6iIF.js +0 -1
- package/assets/devtools-ui/chunk.Ce6_6iIF.js.br +0 -0
- package/assets/devtools-ui/chunk.CpyDMr6O.js +0 -1
- package/assets/devtools-ui/chunk.CpyDMr6O.js.br +0 -0
- package/assets/devtools-ui/chunk.CyPmvPnY.js +0 -1
- package/assets/devtools-ui/chunk.CyPmvPnY.js.br +0 -0
- package/assets/devtools-ui/chunk.DTI_geWu.js +0 -1
- package/assets/devtools-ui/chunk.DTI_geWu.js.br +0 -0
- package/assets/devtools-ui/chunk.DbEH1oOB.js.br +0 -0
- package/assets/devtools-ui/chunk.Ddeqj5gv.js +0 -1
- package/assets/devtools-ui/chunk.Ddeqj5gv.js.br +0 -0
- package/assets/devtools-ui/chunk.DpRnB4vJ.js +0 -1
- package/assets/devtools-ui/chunk.DpRnB4vJ.js.br +0 -0
- package/assets/devtools-ui/chunk.DxPGTlsg.js +0 -1
- package/assets/devtools-ui/chunk.DxPGTlsg.js.br +0 -0
- package/assets/devtools-ui/chunk.G7_MMBJS.js +0 -1
- package/assets/devtools-ui/chunk.G7_MMBJS.js.br +0 -0
- package/assets/devtools-ui/chunk.M6wyKO_3.js.br +0 -0
- package/assets/devtools-ui/chunk.OUxNGmQ6.js +0 -1
- package/assets/devtools-ui/chunk.OUxNGmQ6.js.br +0 -0
- package/assets/devtools-ui/chunk.T1kle-fF.js +0 -1
- package/assets/devtools-ui/chunk.T1kle-fF.js.br +0 -0
- package/assets/devtools-ui/chunk.WjpsbQAv.js +0 -1
- package/assets/devtools-ui/chunk.WjpsbQAv.js.br +0 -0
- package/assets/devtools-ui/chunk.c6YgVx86.js +0 -1
- package/assets/devtools-ui/chunk.c6YgVx86.js.br +0 -0
- package/assets/devtools-ui/chunk.dwU3E_MU.js +0 -1
- package/assets/devtools-ui/chunk.dwU3E_MU.js.br +0 -0
- package/assets/devtools-ui/chunk.lJL-lgnW.js.br +0 -0
- package/assets/devtools-ui/chunk.lPWRmvA-.js +0 -7
- package/assets/devtools-ui/chunk.lPWRmvA-.js.br +0 -0
- package/assets/devtools-ui/chunk.p3HJvugM.js +0 -1
- package/assets/devtools-ui/chunk.p3HJvugM.js.br +0 -0
- package/assets/devtools-ui/chunk.r_Xoa_CI.js +0 -1
- package/assets/devtools-ui/chunk.r_Xoa_CI.js.br +0 -0
- package/assets/devtools-ui/chunk.sRNuTYXb.js +0 -1
- package/assets/devtools-ui/chunk.sRNuTYXb.js.br +0 -0
- package/assets/devtools-ui/chunk.tUjcyX5C.js +0 -1
- package/assets/devtools-ui/chunk.tUjcyX5C.js.br +0 -0
- package/assets/devtools-ui/chunk.thjBxvCA.js +0 -1
- package/assets/devtools-ui/chunk.thjBxvCA.js.br +0 -0
- package/assets/devtools-ui/entry.GYhBVRpC.js +0 -78
- package/assets/devtools-ui/entry.GYhBVRpC.js.br +0 -0
- package/src/server/links/services/DefinitionsPool.spec.ts +0 -86
- package/src/server/links/services/DefinitionsPool.ts +0 -43
|
@@ -82,6 +82,9 @@ export class DockerComposeGenerator {
|
|
|
82
82
|
this.anyAppHas(options.apps, "hasQueue")) &&
|
|
83
83
|
!options.envVars.REDIS_URL;
|
|
84
84
|
|
|
85
|
+
const needsRustFS =
|
|
86
|
+
this.anyAppHas(options.apps, "hasBucket") && !options.envVars.S3_ENDPOINT;
|
|
87
|
+
|
|
85
88
|
if (needsPostgres) {
|
|
86
89
|
const dbName = `${options.project}_${options.env}`.replace(/-/g, "_");
|
|
87
90
|
services.push(
|
|
@@ -110,6 +113,22 @@ export class DockerComposeGenerator {
|
|
|
110
113
|
);
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
if (needsRustFS) {
|
|
117
|
+
services.push(
|
|
118
|
+
[
|
|
119
|
+
" rustfs:",
|
|
120
|
+
" image: rustfs/rustfs:latest",
|
|
121
|
+
' ports: ["9000:9000"]',
|
|
122
|
+
" environment:",
|
|
123
|
+
" RUSTFS_ROOT_USER: alepha",
|
|
124
|
+
" RUSTFS_ROOT_PASSWORD: alepha",
|
|
125
|
+
" volumes:",
|
|
126
|
+
" - rustfs_data:/data",
|
|
127
|
+
].join("\n"),
|
|
128
|
+
);
|
|
129
|
+
volumes.push(" rustfs_data:");
|
|
130
|
+
}
|
|
131
|
+
|
|
113
132
|
if (services.length === 0) {
|
|
114
133
|
return null;
|
|
115
134
|
}
|
|
@@ -197,6 +216,9 @@ export class DockerComposeGenerator {
|
|
|
197
216
|
) {
|
|
198
217
|
deps.push(" - redis");
|
|
199
218
|
}
|
|
219
|
+
if (app.resources.hasBucket && !options.envVars.S3_ENDPOINT) {
|
|
220
|
+
deps.push(" - rustfs");
|
|
221
|
+
}
|
|
200
222
|
if (deps.length > 0) {
|
|
201
223
|
appLines.push(" depends_on:", ...deps);
|
|
202
224
|
}
|
|
@@ -244,6 +266,28 @@ export class DockerComposeGenerator {
|
|
|
244
266
|
services.push(redisLines.join("\n"));
|
|
245
267
|
}
|
|
246
268
|
|
|
269
|
+
// RustFS (S3-compatible object storage)
|
|
270
|
+
const needsRustFS =
|
|
271
|
+
this.anyAppHas(options.apps, "hasBucket") && !options.envVars.S3_ENDPOINT;
|
|
272
|
+
|
|
273
|
+
if (needsRustFS) {
|
|
274
|
+
const rustfsLines = [
|
|
275
|
+
" rustfs:",
|
|
276
|
+
" image: rustfs/rustfs:latest",
|
|
277
|
+
" environment:",
|
|
278
|
+
" RUSTFS_ROOT_USER: alepha",
|
|
279
|
+
" RUSTFS_ROOT_PASSWORD: ${S3_SECRET_KEY}",
|
|
280
|
+
" volumes:",
|
|
281
|
+
" - rustfs_data:/data",
|
|
282
|
+
];
|
|
283
|
+
if (hasDomain) {
|
|
284
|
+
rustfsLines.push(" networks:", " - internal");
|
|
285
|
+
}
|
|
286
|
+
rustfsLines.push(" restart: unless-stopped");
|
|
287
|
+
services.push(rustfsLines.join("\n"));
|
|
288
|
+
volumes.push(" rustfs_data:");
|
|
289
|
+
}
|
|
290
|
+
|
|
247
291
|
const parts = [
|
|
248
292
|
"# Auto-generated by Alepha. Do not edit.",
|
|
249
293
|
"services:",
|
|
@@ -302,7 +346,8 @@ export class DockerComposeGenerator {
|
|
|
302
346
|
return (
|
|
303
347
|
(this.anyAppHas(apps, "hasDatabase") && !envVars.DATABASE_URL) ||
|
|
304
348
|
((this.anyAppHas(apps, "hasKV") || this.anyAppHas(apps, "hasQueue")) &&
|
|
305
|
-
!envVars.REDIS_URL)
|
|
349
|
+
!envVars.REDIS_URL) ||
|
|
350
|
+
(this.anyAppHas(apps, "hasBucket") && !envVars.S3_ENDPOINT)
|
|
306
351
|
);
|
|
307
352
|
}
|
|
308
353
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { describe, test } from "vitest";
|
|
3
|
+
import { SecretFilterService } from "./SecretFilterService.ts";
|
|
4
|
+
|
|
5
|
+
describe("SecretFilterService", () => {
|
|
6
|
+
const createFilter = () => {
|
|
7
|
+
const alepha = Alepha.create();
|
|
8
|
+
return alepha.inject(SecretFilterService);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
test("keeps normal secret keys", ({ expect }) => {
|
|
12
|
+
const filter = createFilter();
|
|
13
|
+
const result = filter.filter({
|
|
14
|
+
API_KEY: "abc123",
|
|
15
|
+
REDIS_URL: "redis://localhost",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(result).toEqual({
|
|
19
|
+
API_KEY: "abc123",
|
|
20
|
+
REDIS_URL: "redis://localhost",
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("keeps DATABASE_URL and POSTGRES_SCHEMA", ({ expect }) => {
|
|
25
|
+
const filter = createFilter();
|
|
26
|
+
const result = filter.filter({
|
|
27
|
+
DATABASE_URL: "postgres://localhost/db",
|
|
28
|
+
POSTGRES_SCHEMA: "public",
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
expect(result).toEqual({
|
|
32
|
+
DATABASE_URL: "postgres://localhost/db",
|
|
33
|
+
POSTGRES_SCHEMA: "public",
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("excludes NODE_ENV", ({ expect }) => {
|
|
38
|
+
const filter = createFilter();
|
|
39
|
+
const result = filter.filter({
|
|
40
|
+
NODE_ENV: "production",
|
|
41
|
+
API_KEY: "abc123",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(result).toEqual({ API_KEY: "abc123" });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("excludes VITE_ prefixed keys", ({ expect }) => {
|
|
48
|
+
const filter = createFilter();
|
|
49
|
+
const result = filter.filter({
|
|
50
|
+
VITE_APP_TITLE: "My App",
|
|
51
|
+
VITE_PUBLIC_KEY: "pk_123",
|
|
52
|
+
API_KEY: "abc123",
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(result).toEqual({ API_KEY: "abc123" });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("excludes empty values", ({ expect }) => {
|
|
59
|
+
const filter = createFilter();
|
|
60
|
+
const result = filter.filter({
|
|
61
|
+
API_KEY: "abc123",
|
|
62
|
+
EMPTY_VAR: "",
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(result).toEqual({ API_KEY: "abc123" });
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("returns empty record when all filtered", ({ expect }) => {
|
|
69
|
+
const filter = createFilter();
|
|
70
|
+
const result = filter.filter({
|
|
71
|
+
NODE_ENV: "production",
|
|
72
|
+
VITE_KEY: "value",
|
|
73
|
+
EMPTY: "",
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual({});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("toRemoteName", () => {
|
|
80
|
+
test("prefixes GITHUB_ keys with APP_", ({ expect }) => {
|
|
81
|
+
const filter = createFilter();
|
|
82
|
+
expect(filter.toRemoteName("GITHUB_CLIENT_ID")).toBe(
|
|
83
|
+
"APP_GITHUB_CLIENT_ID",
|
|
84
|
+
);
|
|
85
|
+
expect(filter.toRemoteName("GITHUB_CLIENT_SECRET")).toBe(
|
|
86
|
+
"APP_GITHUB_CLIENT_SECRET",
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("leaves non-GITHUB_ keys unchanged", ({ expect }) => {
|
|
91
|
+
const filter = createFilter();
|
|
92
|
+
expect(filter.toRemoteName("DATABASE_URL")).toBe("DATABASE_URL");
|
|
93
|
+
expect(filter.toRemoteName("API_KEY")).toBe("API_KEY");
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe("toLocalName", () => {
|
|
98
|
+
test("strips APP_ prefix from APP_GITHUB_ keys", ({ expect }) => {
|
|
99
|
+
const filter = createFilter();
|
|
100
|
+
expect(filter.toLocalName("APP_GITHUB_CLIENT_ID")).toBe(
|
|
101
|
+
"GITHUB_CLIENT_ID",
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("leaves non-APP_GITHUB_ keys unchanged", ({ expect }) => {
|
|
106
|
+
const filter = createFilter();
|
|
107
|
+
expect(filter.toLocalName("DATABASE_URL")).toBe("DATABASE_URL");
|
|
108
|
+
expect(filter.toLocalName("APP_SECRET")).toBe("APP_SECRET");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters environment variables for secret store syncing.
|
|
3
|
+
*
|
|
4
|
+
* Excludes platform-managed vars (NODE_ENV), build-time vars (VITE_*),
|
|
5
|
+
* and empty values. Keeps everything else — including DATABASE_URL
|
|
6
|
+
* and POSTGRES_SCHEMA which GitHub Actions needs.
|
|
7
|
+
*
|
|
8
|
+
* Also handles renaming GITHUB_* keys since GitHub Actions rejects
|
|
9
|
+
* secret names starting with GITHUB_.
|
|
10
|
+
*/
|
|
11
|
+
export class SecretFilterService {
|
|
12
|
+
protected static readonly EXCLUDED_KEYS = new Set(["NODE_ENV"]);
|
|
13
|
+
protected static readonly GITHUB_PREFIX = "GITHUB_";
|
|
14
|
+
protected static readonly REMOTE_PREFIX = "APP_GITHUB_";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Return only the entries that should be pushed to a secret store.
|
|
18
|
+
*/
|
|
19
|
+
public filter(envVars: Record<string, string>): Record<string, string> {
|
|
20
|
+
const result: Record<string, string> = {};
|
|
21
|
+
|
|
22
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
23
|
+
if (!value) continue;
|
|
24
|
+
if (SecretFilterService.EXCLUDED_KEYS.has(key)) continue;
|
|
25
|
+
if (key.startsWith("VITE_")) continue;
|
|
26
|
+
result[key] = value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Convert a local env key to a remote secret name.
|
|
34
|
+
*
|
|
35
|
+
* GITHUB_* keys are prefixed with APP_ since GitHub Actions rejects
|
|
36
|
+
* secret names starting with GITHUB_.
|
|
37
|
+
*/
|
|
38
|
+
public toRemoteName(key: string): string {
|
|
39
|
+
if (key.startsWith(SecretFilterService.GITHUB_PREFIX)) {
|
|
40
|
+
return `${SecretFilterService.REMOTE_PREFIX}${key.slice(SecretFilterService.GITHUB_PREFIX.length)}`;
|
|
41
|
+
}
|
|
42
|
+
return key;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Convert a remote secret name back to the local env key.
|
|
47
|
+
*/
|
|
48
|
+
public toLocalName(remoteName: string): string {
|
|
49
|
+
if (remoteName.startsWith(SecretFilterService.REMOTE_PREFIX)) {
|
|
50
|
+
return `${SecretFilterService.GITHUB_PREFIX}${remoteName.slice(SecretFilterService.REMOTE_PREFIX.length)}`;
|
|
51
|
+
}
|
|
52
|
+
return remoteName;
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/core/Alepha.ts
CHANGED
|
@@ -236,9 +236,22 @@ export class Alepha {
|
|
|
236
236
|
protected ready = false;
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
|
-
*
|
|
239
|
+
* In-flight startup promise returned by boot().
|
|
240
|
+
*
|
|
241
|
+
* Concurrent callers of start() share this same promise. Cleared on
|
|
242
|
+
* success, failure, or stale-detection.
|
|
243
|
+
*/
|
|
244
|
+
protected startPromise?: Promise<this>;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Timestamp (performance.now) when the current boot() began.
|
|
248
|
+
*
|
|
249
|
+
* In serverless environments (e.g. Cloudflare Workers), the runtime can
|
|
250
|
+
* kill an invocation mid-startup without running cleanup. The global
|
|
251
|
+
* Alepha instance persists, leaving startPromise as a never-settling
|
|
252
|
+
* promise. We detect this by comparing elapsed time against STARTUP_TIMEOUT.
|
|
240
253
|
*/
|
|
241
|
-
protected
|
|
254
|
+
protected startedAt = 0;
|
|
242
255
|
|
|
243
256
|
/**
|
|
244
257
|
* During the instantiation process, we keep a list of pending instantiations.
|
|
@@ -479,6 +492,17 @@ export class Alepha {
|
|
|
479
492
|
|
|
480
493
|
// -------------------------------------------------------------------------------------------------------------------
|
|
481
494
|
|
|
495
|
+
/**
|
|
496
|
+
* Max time (ms) a boot() is allowed to run before being considered stale.
|
|
497
|
+
*
|
|
498
|
+
* In serverless runtimes (Cloudflare Workers, etc.) an invocation can be
|
|
499
|
+
* killed mid-startup. The global Alepha instance survives, but
|
|
500
|
+
* `startPromise` becomes a zombie that never settles.
|
|
501
|
+
* Any new invocation that sees an older-than-STARTUP_TIMEOUT promise
|
|
502
|
+
* discards it and boots fresh.
|
|
503
|
+
*/
|
|
504
|
+
protected static readonly STARTUP_TIMEOUT = 30_000;
|
|
505
|
+
|
|
482
506
|
/**
|
|
483
507
|
* Starts the App.
|
|
484
508
|
*
|
|
@@ -487,6 +511,10 @@ export class Alepha {
|
|
|
487
511
|
* - Run "start" hook for all services. Providers will connect/listen/...
|
|
488
512
|
* - Run "ready" hook for all services. This is the point where the App is ready to serve requests.
|
|
489
513
|
*
|
|
514
|
+
* Concurrent callers share the same boot promise. If a previous boot was
|
|
515
|
+
* abandoned (serverless invocation killed), the stale promise is detected
|
|
516
|
+
* and a fresh boot is triggered.
|
|
517
|
+
*
|
|
490
518
|
* @return A promise that resolves when the App has started.
|
|
491
519
|
*/
|
|
492
520
|
public async start(): Promise<this> {
|
|
@@ -495,19 +523,36 @@ export class Alepha {
|
|
|
495
523
|
return this;
|
|
496
524
|
}
|
|
497
525
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
526
|
+
if (this.startPromise) {
|
|
527
|
+
const elapsed = performance.now() - this.startedAt;
|
|
528
|
+
if (elapsed > Alepha.STARTUP_TIMEOUT) {
|
|
529
|
+
this.log?.warn(
|
|
530
|
+
`Previous start attempt is stale (${Math.round(elapsed)}ms ago), resetting...`,
|
|
531
|
+
);
|
|
532
|
+
this.resetStartup();
|
|
533
|
+
} else {
|
|
534
|
+
this.log?.warn("App is already starting, waiting for it to finish...");
|
|
535
|
+
return this.startPromise;
|
|
536
|
+
}
|
|
502
537
|
}
|
|
503
538
|
|
|
504
|
-
this.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
539
|
+
this.startedAt = performance.now();
|
|
540
|
+
this.startPromise = this.boot();
|
|
541
|
+
return this.startPromise;
|
|
542
|
+
}
|
|
508
543
|
|
|
509
|
-
|
|
544
|
+
/**
|
|
545
|
+
* Perform the actual startup sequence.
|
|
546
|
+
*
|
|
547
|
+
* Separated from start() so that start() remains a thin state-machine
|
|
548
|
+
* and boot() owns the real work. The promise returned here is stored as
|
|
549
|
+
* `startPromise` and shared with concurrent callers.
|
|
550
|
+
*/
|
|
551
|
+
protected async boot(): Promise<this> {
|
|
552
|
+
const now = performance.now();
|
|
553
|
+
this.log?.info("Starting App...");
|
|
510
554
|
|
|
555
|
+
try {
|
|
511
556
|
for (const [key] of this.substitutions.entries()) {
|
|
512
557
|
this.inject(key);
|
|
513
558
|
}
|
|
@@ -544,17 +589,27 @@ export class Alepha {
|
|
|
544
589
|
);
|
|
545
590
|
|
|
546
591
|
this.ready = true;
|
|
592
|
+
return this;
|
|
547
593
|
} catch (error) {
|
|
548
|
-
this.
|
|
549
|
-
|
|
550
|
-
this.starting = undefined;
|
|
551
|
-
return promise;
|
|
594
|
+
this.resetStartup();
|
|
595
|
+
throw error;
|
|
552
596
|
}
|
|
597
|
+
}
|
|
553
598
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
599
|
+
/**
|
|
600
|
+
* Reset startup state so that a fresh boot() can be attempted.
|
|
601
|
+
*
|
|
602
|
+
* Called when:
|
|
603
|
+
* - boot() fails (error during configure/start/ready hooks)
|
|
604
|
+
* - a stale startPromise is detected (serverless invocation was killed)
|
|
605
|
+
*/
|
|
606
|
+
protected resetStartup(): void {
|
|
607
|
+
this.startPromise = undefined;
|
|
608
|
+
this.startedAt = 0;
|
|
609
|
+
this.locked = false;
|
|
610
|
+
this.configured = false;
|
|
611
|
+
this.started = false;
|
|
612
|
+
this.ready = false;
|
|
558
613
|
}
|
|
559
614
|
|
|
560
615
|
/**
|
|
@@ -580,6 +635,8 @@ export class Alepha {
|
|
|
580
635
|
|
|
581
636
|
this.started = false;
|
|
582
637
|
this.ready = false;
|
|
638
|
+
this.startPromise = undefined;
|
|
639
|
+
this.startedAt = 0;
|
|
583
640
|
}
|
|
584
641
|
|
|
585
642
|
/**
|
|
@@ -893,13 +950,20 @@ export class Alepha {
|
|
|
893
950
|
|
|
894
951
|
const config = this.codec.validate(schema, this.env) as Record<string, any>;
|
|
895
952
|
|
|
896
|
-
|
|
897
|
-
|
|
953
|
+
// Resolve $KEY references. Multiple passes handle transitive references
|
|
954
|
+
// where a replacement introduces a new $KEY that was already checked
|
|
955
|
+
// (e.g. C=$B, B=$A, A=value — single pass leaves C as "$A").
|
|
956
|
+
let changed = true;
|
|
957
|
+
for (let pass = 0; changed && pass < 10; pass++) {
|
|
958
|
+
changed = false;
|
|
959
|
+
for (const key in config) {
|
|
960
|
+
if (typeof config[key] !== "string") continue;
|
|
898
961
|
for (const env in config) {
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
962
|
+
const before = config[key] as string;
|
|
963
|
+
config[key] = before.replaceAll(`$${env}`, String(config[env] ?? ""));
|
|
964
|
+
if (config[key] !== before) {
|
|
965
|
+
changed = true;
|
|
966
|
+
}
|
|
903
967
|
}
|
|
904
968
|
}
|
|
905
969
|
}
|
|
@@ -1160,6 +1224,11 @@ export interface Env {
|
|
|
1160
1224
|
* Optional root module name.
|
|
1161
1225
|
*/
|
|
1162
1226
|
MODULE_NAME?: string;
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* The secret key used for signing JWTs, encrypting cookies, and other security features.
|
|
1230
|
+
*/
|
|
1231
|
+
APP_SECRET?: string;
|
|
1163
1232
|
}
|
|
1164
1233
|
|
|
1165
1234
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
@@ -84,6 +84,26 @@ describe("Alepha#parseEnv", () => {
|
|
|
84
84
|
expect(env.URL).toBe("$host");
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
+
it("should resolve transitive $KEY references", async () => {
|
|
88
|
+
const schema = t.object({
|
|
89
|
+
A: t.optional(t.text()),
|
|
90
|
+
B: t.optional(t.text()),
|
|
91
|
+
C: t.optional(t.text()),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const alepha = Alepha.create({
|
|
95
|
+
env: {
|
|
96
|
+
A: "value",
|
|
97
|
+
B: "$A",
|
|
98
|
+
C: "$B",
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const env = alepha.parseEnv(schema);
|
|
103
|
+
expect(env.B).toBe("value");
|
|
104
|
+
expect(env.C).toBe("value");
|
|
105
|
+
});
|
|
106
|
+
|
|
87
107
|
it("should return cached result for same schema", async () => {
|
|
88
108
|
const schema = t.object({
|
|
89
109
|
FOO: t.optional(t.text()),
|
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
import { createMiddleware, type Middleware } from "alepha";
|
|
2
2
|
|
|
3
|
-
export interface MemoizeOptions {
|
|
4
|
-
/**
|
|
5
|
-
* Maximum number of entries to keep in the cache.
|
|
6
|
-
* When exceeded, the oldest entry is evicted (FIFO).
|
|
7
|
-
*
|
|
8
|
-
* @default 1000
|
|
9
|
-
*/
|
|
10
|
-
max?: number;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Custom key function. Receives the handler's arguments.
|
|
14
|
-
* By default, `JSON.stringify(args)` is used.
|
|
15
|
-
*/
|
|
16
|
-
key?: (...args: any[]) => string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
3
|
/**
|
|
20
4
|
* Lightweight in-process memoization middleware.
|
|
21
5
|
*
|
|
@@ -48,20 +32,48 @@ export const $memoize = (options?: MemoizeOptions): Middleware => {
|
|
|
48
32
|
return store.get(key);
|
|
49
33
|
}
|
|
50
34
|
|
|
51
|
-
|
|
35
|
+
// Store the promise immediately to deduplicate concurrent calls
|
|
36
|
+
// for the same key (thundering herd prevention).
|
|
37
|
+
const promise = next(...args);
|
|
38
|
+
store.set(key, promise);
|
|
52
39
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const firstKey = store.keys().next().value;
|
|
56
|
-
if (firstKey !== undefined) {
|
|
57
|
-
store.delete(firstKey);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
40
|
+
try {
|
|
41
|
+
const result = await promise;
|
|
60
42
|
|
|
61
|
-
|
|
43
|
+
// Replace the promise with the resolved value
|
|
44
|
+
store.set(key, result);
|
|
62
45
|
|
|
63
|
-
|
|
46
|
+
// Evict oldest if at capacity
|
|
47
|
+
if (store.size > maxSize) {
|
|
48
|
+
const firstKey = store.keys().next().value;
|
|
49
|
+
if (firstKey !== undefined) {
|
|
50
|
+
store.delete(firstKey);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
// Don't cache failed results
|
|
57
|
+
store.delete(key);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
64
60
|
};
|
|
65
61
|
},
|
|
66
62
|
});
|
|
67
63
|
};
|
|
64
|
+
|
|
65
|
+
export interface MemoizeOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Maximum number of entries to keep in the cache.
|
|
68
|
+
* When exceeded, the oldest entry is evicted (FIFO).
|
|
69
|
+
*
|
|
70
|
+
* @default 1000
|
|
71
|
+
*/
|
|
72
|
+
max?: number;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Custom key function. Receives the handler's arguments.
|
|
76
|
+
* By default, `JSON.stringify(args)` is used.
|
|
77
|
+
*/
|
|
78
|
+
key?: (...args: any[]) => string;
|
|
79
|
+
}
|
|
@@ -27,6 +27,8 @@ export class AlsProvider {
|
|
|
27
27
|
|
|
28
28
|
const parent = this.als.getStore() ?? undefined;
|
|
29
29
|
|
|
30
|
+
// Intentional mutation: set defaults on the input object to avoid
|
|
31
|
+
// allocating an intermediate copy. Callers always pass a fresh literal.
|
|
30
32
|
data.registry ??= new Map();
|
|
31
33
|
data.context ??= this.createContextId();
|
|
32
34
|
|
|
@@ -238,6 +238,10 @@ export class EventManager {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
const catchErrors = options.catch ?? false;
|
|
241
|
+
|
|
242
|
+
// Logger is captured at compile time. Since compilation happens after
|
|
243
|
+
// start() (on first emit), the logger is already fully configured and
|
|
244
|
+
// won't change afterwards — this is safe.
|
|
241
245
|
const log = this.log;
|
|
242
246
|
|
|
243
247
|
// Once the first async hook is encountered, all remaining hooks
|
|
@@ -836,12 +836,9 @@ describe("KeylessJsonSchemaCodec", () => {
|
|
|
836
836
|
const alepha = Alepha.create();
|
|
837
837
|
const codec = alepha.inject(KeylessJsonSchemaCodec);
|
|
838
838
|
|
|
839
|
-
// Configure
|
|
839
|
+
// Configure options
|
|
840
840
|
codec.configure({
|
|
841
841
|
useFunctionCompilation: false,
|
|
842
|
-
maxArrayLength: 100,
|
|
843
|
-
maxStringLength: 1000,
|
|
844
|
-
maxDepth: 10,
|
|
845
842
|
});
|
|
846
843
|
|
|
847
844
|
// Test that configuration works by encoding/decoding
|