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
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type TSchema,
|
|
9
9
|
t,
|
|
10
10
|
} from "alepha";
|
|
11
|
+
import { DateTimeProvider } from "alepha/datetime";
|
|
11
12
|
import { $logger } from "alepha/logger";
|
|
12
13
|
import { AlephaContext, ClientOnly } from "alepha/react";
|
|
13
14
|
import type { Head } from "alepha/react/head";
|
|
@@ -24,6 +25,8 @@ import {
|
|
|
24
25
|
type PagePrimitiveOptions,
|
|
25
26
|
} from "../primitives/$page.ts";
|
|
26
27
|
|
|
28
|
+
// -------------------------------------------------------------------------------------------------------------------
|
|
29
|
+
|
|
27
30
|
export const reactPageOptions = $atom({
|
|
28
31
|
name: "alepha.react.page.options",
|
|
29
32
|
description: "Configuration options for the React page provider.",
|
|
@@ -32,20 +35,87 @@ export const reactPageOptions = $atom({
|
|
|
32
35
|
* Enable React StrictMode wrapper.
|
|
33
36
|
*/
|
|
34
37
|
strictMode: t.boolean({ default: true }),
|
|
38
|
+
/**
|
|
39
|
+
* RegExp pattern (as string) to detect file-like URLs (e.g. /hello.txt, /wp-login.php).
|
|
40
|
+
* When a request hits the catch-all wildcard route and matches this pattern,
|
|
41
|
+
* SSR is skipped and a plain 404 response is returned instead.
|
|
42
|
+
*
|
|
43
|
+
* Set to empty string to disable this behavior.
|
|
44
|
+
*
|
|
45
|
+
* @default "\\.[a-zA-Z0-9]{1,10}$"
|
|
46
|
+
*/
|
|
47
|
+
staticFilePattern: t.string(),
|
|
35
48
|
}),
|
|
36
49
|
default: {
|
|
37
50
|
strictMode: true,
|
|
51
|
+
staticFilePattern: "\\.[a-zA-Z0-9]{1,10}$",
|
|
38
52
|
},
|
|
39
53
|
});
|
|
40
54
|
|
|
55
|
+
// -------------------------------------------------------------------------------------------------------------------
|
|
56
|
+
|
|
41
57
|
/**
|
|
42
58
|
* Handle page routes for React applications. (Browser and Server)
|
|
43
59
|
*/
|
|
44
60
|
export class ReactPageProvider {
|
|
61
|
+
protected readonly dateTimeProvider = $inject(DateTimeProvider);
|
|
45
62
|
protected readonly log = $logger();
|
|
46
63
|
protected readonly options = $use(reactPageOptions);
|
|
47
64
|
protected readonly alepha = $inject(Alepha);
|
|
48
65
|
protected readonly pages: PageRoute[] = [];
|
|
66
|
+
protected nextIdCursor = 0;
|
|
67
|
+
|
|
68
|
+
protected readonly configure = $hook({
|
|
69
|
+
on: "configure",
|
|
70
|
+
handler: () => {
|
|
71
|
+
let hasNotFoundHandler = false;
|
|
72
|
+
const pages = this.alepha.primitives($page);
|
|
73
|
+
|
|
74
|
+
const hasParent = (it: PagePrimitive) => {
|
|
75
|
+
if (it.options.parent) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (const page of pages) {
|
|
80
|
+
const children = page.options.children
|
|
81
|
+
? Array.isArray(page.options.children)
|
|
82
|
+
? page.options.children
|
|
83
|
+
: page.options.children()
|
|
84
|
+
: [];
|
|
85
|
+
if (children.includes(it)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
for (const page of pages) {
|
|
92
|
+
if (page.options.path === "/*") {
|
|
93
|
+
hasNotFoundHandler = true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// skip children, we only want root pages
|
|
97
|
+
if (hasParent(page)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.add(this.map(pages, page));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!hasNotFoundHandler && pages.length > 0) {
|
|
105
|
+
// add a default 404 page if not already defined
|
|
106
|
+
this.add({
|
|
107
|
+
path: "/*",
|
|
108
|
+
name: "notFound",
|
|
109
|
+
component: NotFoundPage,
|
|
110
|
+
onServerResponse: ({ reply }) => {
|
|
111
|
+
reply.status = 404;
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// -------------------------------------------------------------------------------------------------------------------
|
|
49
119
|
|
|
50
120
|
public getPages(): PageRoute[] {
|
|
51
121
|
return this.pages;
|
|
@@ -210,7 +280,7 @@ export class ReactPageProvider {
|
|
|
210
280
|
? this.alepha.codec.decode(route.schema.query, state.query)
|
|
211
281
|
: {};
|
|
212
282
|
} catch (e) {
|
|
213
|
-
it.error = e
|
|
283
|
+
it.error = e instanceof Error ? e : new Error(String(e));
|
|
214
284
|
break;
|
|
215
285
|
}
|
|
216
286
|
|
|
@@ -219,7 +289,7 @@ export class ReactPageProvider {
|
|
|
219
289
|
? this.alepha.codec.decode(route.schema.params, state.params)
|
|
220
290
|
: {};
|
|
221
291
|
} catch (e) {
|
|
222
|
-
it.error = e
|
|
292
|
+
it.error = e instanceof Error ? e : new Error(String(e));
|
|
223
293
|
break;
|
|
224
294
|
}
|
|
225
295
|
|
|
@@ -258,6 +328,11 @@ export class ReactPageProvider {
|
|
|
258
328
|
forceRefresh = true;
|
|
259
329
|
}
|
|
260
330
|
|
|
331
|
+
// redirect shorthand
|
|
332
|
+
if (route.redirect) {
|
|
333
|
+
return { redirect: route.redirect };
|
|
334
|
+
}
|
|
335
|
+
|
|
261
336
|
// no loader, render a basic view by default
|
|
262
337
|
if (!route.loader) {
|
|
263
338
|
continue;
|
|
@@ -288,7 +363,7 @@ export class ReactPageProvider {
|
|
|
288
363
|
|
|
289
364
|
this.log.error("Page loader has failed", e);
|
|
290
365
|
|
|
291
|
-
it.error = e
|
|
366
|
+
it.error = e instanceof Error ? e : new Error(String(e));
|
|
292
367
|
break;
|
|
293
368
|
}
|
|
294
369
|
}
|
|
@@ -322,14 +397,18 @@ export class ReactPageProvider {
|
|
|
322
397
|
// normal use case
|
|
323
398
|
if (!it.error) {
|
|
324
399
|
try {
|
|
325
|
-
const element = await this.createElement(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
400
|
+
const element = await this.createElement(
|
|
401
|
+
it.route,
|
|
402
|
+
{
|
|
403
|
+
// default props attached to page
|
|
404
|
+
...(it.route.props ? it.route.props() : {}),
|
|
405
|
+
// resolved props
|
|
406
|
+
...props,
|
|
407
|
+
// context props (from previous layers)
|
|
408
|
+
...context,
|
|
409
|
+
},
|
|
410
|
+
state.url,
|
|
411
|
+
);
|
|
333
412
|
|
|
334
413
|
state.layers.push({
|
|
335
414
|
name: it.route.name,
|
|
@@ -343,7 +422,7 @@ export class ReactPageProvider {
|
|
|
343
422
|
cache: it.cache,
|
|
344
423
|
});
|
|
345
424
|
} catch (e) {
|
|
346
|
-
it.error = e
|
|
425
|
+
it.error = e instanceof Error ? e : new Error(String(e));
|
|
347
426
|
}
|
|
348
427
|
}
|
|
349
428
|
|
|
@@ -377,6 +456,7 @@ export class ReactPageProvider {
|
|
|
377
456
|
index: i + 1,
|
|
378
457
|
path,
|
|
379
458
|
route: it.route,
|
|
459
|
+
cache: it.cache,
|
|
380
460
|
});
|
|
381
461
|
break;
|
|
382
462
|
} catch (e) {
|
|
@@ -405,6 +485,7 @@ export class ReactPageProvider {
|
|
|
405
485
|
protected async createElement(
|
|
406
486
|
page: PageRoute,
|
|
407
487
|
props: Record<string, any>,
|
|
488
|
+
targetUrl?: URL,
|
|
408
489
|
): Promise<ReactNode> {
|
|
409
490
|
if (page.lazy && page.component) {
|
|
410
491
|
this.log.warn(
|
|
@@ -413,8 +494,17 @@ export class ReactPageProvider {
|
|
|
413
494
|
}
|
|
414
495
|
|
|
415
496
|
if (page.lazy) {
|
|
416
|
-
|
|
417
|
-
|
|
497
|
+
try {
|
|
498
|
+
const component = await page.lazy();
|
|
499
|
+
return createElement(component.default, props);
|
|
500
|
+
} catch (error) {
|
|
501
|
+
if (this.alepha.isBrowser() && this.isChunkLoadError(error)) {
|
|
502
|
+
if (this.reloadAfterChunkError(targetUrl)) {
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
throw error;
|
|
507
|
+
}
|
|
418
508
|
}
|
|
419
509
|
|
|
420
510
|
if (page.component) {
|
|
@@ -424,6 +514,46 @@ export class ReactPageProvider {
|
|
|
424
514
|
return undefined;
|
|
425
515
|
}
|
|
426
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Detect chunk load errors caused by stale dynamic imports after a deployment.
|
|
519
|
+
* When new assets are deployed with different hashes, old chunk URLs return 404.
|
|
520
|
+
*/
|
|
521
|
+
protected isChunkLoadError(error: unknown): boolean {
|
|
522
|
+
if (!(error instanceof Error)) return false;
|
|
523
|
+
const msg = error.message;
|
|
524
|
+
return (
|
|
525
|
+
/Failed to fetch dynamically imported module/.test(msg) ||
|
|
526
|
+
/error loading dynamically imported module/i.test(msg) ||
|
|
527
|
+
/Unable to preload CSS/.test(msg) ||
|
|
528
|
+
/Importing a module script failed/.test(msg)
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Navigate to the target URL to fetch updated assets after a chunk load failure.
|
|
534
|
+
* Uses sessionStorage to prevent infinite reload loops.
|
|
535
|
+
* Returns true if navigation was initiated.
|
|
536
|
+
*/
|
|
537
|
+
protected reloadAfterChunkError(url?: URL): boolean {
|
|
538
|
+
const key = "alepha:chunk-reload";
|
|
539
|
+
const lastReload = sessionStorage.getItem(key);
|
|
540
|
+
const now = this.dateTimeProvider.nowMillis();
|
|
541
|
+
|
|
542
|
+
if (lastReload && now - Number(lastReload) < 10_000) {
|
|
543
|
+
this.log.error(
|
|
544
|
+
"Chunk load failed after recent reload, not retrying to avoid loop",
|
|
545
|
+
);
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
this.log.warn("Chunk load failed after deployment, reloading page");
|
|
550
|
+
sessionStorage.setItem(key, String(now));
|
|
551
|
+
window.location.assign(
|
|
552
|
+
url ? url.pathname + url.search : window.location.href,
|
|
553
|
+
);
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
|
|
427
557
|
public renderError(error: Error): ReactNode {
|
|
428
558
|
return createElement(ErrorViewer, { error, alepha: this.alepha });
|
|
429
559
|
}
|
|
@@ -490,56 +620,6 @@ export class ReactPageProvider {
|
|
|
490
620
|
);
|
|
491
621
|
}
|
|
492
622
|
|
|
493
|
-
protected readonly configure = $hook({
|
|
494
|
-
on: "configure",
|
|
495
|
-
handler: () => {
|
|
496
|
-
let hasNotFoundHandler = false;
|
|
497
|
-
const pages = this.alepha.primitives($page);
|
|
498
|
-
|
|
499
|
-
const hasParent = (it: PagePrimitive) => {
|
|
500
|
-
if (it.options.parent) {
|
|
501
|
-
return true;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
for (const page of pages) {
|
|
505
|
-
const children = page.options.children
|
|
506
|
-
? Array.isArray(page.options.children)
|
|
507
|
-
? page.options.children
|
|
508
|
-
: page.options.children()
|
|
509
|
-
: [];
|
|
510
|
-
if (children.includes(it)) {
|
|
511
|
-
return true;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
for (const page of pages) {
|
|
517
|
-
if (page.options.path === "/*") {
|
|
518
|
-
hasNotFoundHandler = true;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// skip children, we only want root pages
|
|
522
|
-
if (hasParent(page)) {
|
|
523
|
-
continue;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
this.add(this.map(pages, page));
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (!hasNotFoundHandler && pages.length > 0) {
|
|
530
|
-
// add a default 404 page if not already defined
|
|
531
|
-
this.add({
|
|
532
|
-
path: "/*",
|
|
533
|
-
name: "notFound",
|
|
534
|
-
component: NotFoundPage,
|
|
535
|
-
onServerResponse: ({ reply }) => {
|
|
536
|
-
reply.status = 404;
|
|
537
|
-
},
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
},
|
|
541
|
-
});
|
|
542
|
-
|
|
543
623
|
protected map(
|
|
544
624
|
pages: Array<PagePrimitive>,
|
|
545
625
|
target: PagePrimitive,
|
|
@@ -607,14 +687,14 @@ export class ReactPageProvider {
|
|
|
607
687
|
return path;
|
|
608
688
|
}
|
|
609
689
|
|
|
610
|
-
protected _next = 0;
|
|
611
|
-
|
|
612
690
|
protected nextId(): string {
|
|
613
|
-
this.
|
|
614
|
-
return `P${this.
|
|
691
|
+
this.nextIdCursor += 1;
|
|
692
|
+
return `P${this.nextIdCursor}`;
|
|
615
693
|
}
|
|
616
694
|
}
|
|
617
695
|
|
|
696
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
697
|
+
|
|
618
698
|
export const isPageRoute = (it: any): it is PageRoute => {
|
|
619
699
|
return (
|
|
620
700
|
it &&
|
|
@@ -644,6 +724,11 @@ export interface PageRoute extends PageRouteEntry {
|
|
|
644
724
|
name: string;
|
|
645
725
|
parent?: PageRoute;
|
|
646
726
|
match: string;
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Optional meta information associated with the page route, can be used for any purpose (e.g. menu label, icon, etc.).
|
|
730
|
+
*/
|
|
731
|
+
label?: string;
|
|
647
732
|
}
|
|
648
733
|
|
|
649
734
|
export interface Layer {
|
|
@@ -709,7 +794,9 @@ export interface ReactRouterState {
|
|
|
709
794
|
*/
|
|
710
795
|
head: Head;
|
|
711
796
|
|
|
712
|
-
|
|
797
|
+
/**
|
|
798
|
+
* Optional name of the current page route
|
|
799
|
+
*/
|
|
713
800
|
name?: string;
|
|
714
801
|
}
|
|
715
802
|
|
|
@@ -721,10 +808,6 @@ export interface RouterStackItem {
|
|
|
721
808
|
cache?: boolean;
|
|
722
809
|
}
|
|
723
810
|
|
|
724
|
-
export interface TransitionOptions {
|
|
725
|
-
previous?: PreviousLayerData[];
|
|
726
|
-
}
|
|
727
|
-
|
|
728
811
|
export interface CreateLayersResult {
|
|
729
812
|
redirect?: string;
|
|
730
813
|
state?: ReactRouterState;
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
type PageRoute,
|
|
30
30
|
ReactPageProvider,
|
|
31
31
|
type ReactRouterState,
|
|
32
|
+
reactPageOptions,
|
|
32
33
|
} from "./ReactPageProvider.ts";
|
|
33
34
|
import { ReactServerTemplateProvider } from "./ReactServerTemplateProvider.ts";
|
|
34
35
|
import { SSRManifestProvider } from "./SSRManifestProvider.ts";
|
|
@@ -72,6 +73,7 @@ export class ReactServerProvider {
|
|
|
72
73
|
protected hasServerLinksProvider = false;
|
|
73
74
|
|
|
74
75
|
protected readonly options = $use(reactServerOptions);
|
|
76
|
+
protected readonly pageOptions = $use(reactPageOptions);
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
79
|
* Configure the React server provider.
|
|
@@ -124,7 +126,7 @@ export class ReactServerProvider {
|
|
|
124
126
|
this.hasServerLinksProvider = this.alepha.has(ServerLinksProvider);
|
|
125
127
|
|
|
126
128
|
for (const page of this.pageApi.getPages()) {
|
|
127
|
-
if (page.component || page.lazy) {
|
|
129
|
+
if (page.component || page.lazy || page.redirect) {
|
|
128
130
|
this.log.debug(`+ ${page.match} -> ${page.name}`);
|
|
129
131
|
|
|
130
132
|
// Separate $cache from server-level middleware.
|
|
@@ -250,6 +252,16 @@ export class ReactServerProvider {
|
|
|
250
252
|
});
|
|
251
253
|
}
|
|
252
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Resolve the static file pattern from page options.
|
|
257
|
+
* Returns a compiled RegExp, or `false` if disabled (empty string).
|
|
258
|
+
*/
|
|
259
|
+
protected resolveStaticFilePattern(): RegExp | false {
|
|
260
|
+
const pattern = this.pageOptions.staticFilePattern;
|
|
261
|
+
if (!pattern) return false;
|
|
262
|
+
return new RegExp(pattern);
|
|
263
|
+
}
|
|
264
|
+
|
|
253
265
|
/**
|
|
254
266
|
* Create the request handler for a page route.
|
|
255
267
|
*
|
|
@@ -261,10 +273,23 @@ export class ReactServerProvider {
|
|
|
261
273
|
cacheMiddleware: Middleware[] = [],
|
|
262
274
|
): ServerHandler {
|
|
263
275
|
const hasCache = cacheMiddleware.length > 0;
|
|
276
|
+
const isCatchAll = route.match === "/*";
|
|
277
|
+
const staticFilePattern = isCatchAll
|
|
278
|
+
? this.resolveStaticFilePattern()
|
|
279
|
+
: false;
|
|
264
280
|
|
|
265
281
|
return async (serverRequest) => {
|
|
266
282
|
const { url, reply, query, params } = serverRequest;
|
|
267
283
|
|
|
284
|
+
// Skip SSR for file-like URLs hitting the catch-all wildcard.
|
|
285
|
+
// Bots and crawlers often probe paths like /hello.txt, /wp-login.php, etc.
|
|
286
|
+
// Rendering a full React page for these is wasteful — return a plain 404 instead.
|
|
287
|
+
if (staticFilePattern && staticFilePattern.test(url.pathname)) {
|
|
288
|
+
reply.status = 404;
|
|
289
|
+
reply.headers["content-type"] = "text/plain";
|
|
290
|
+
return "Not Found";
|
|
291
|
+
}
|
|
292
|
+
|
|
268
293
|
this.log.trace("Rendering page", { name: route.name });
|
|
269
294
|
|
|
270
295
|
// Initialize router state
|
|
@@ -366,6 +391,7 @@ export class ReactServerProvider {
|
|
|
366
391
|
},
|
|
367
392
|
{
|
|
368
393
|
hydration: true,
|
|
394
|
+
state,
|
|
369
395
|
onError: (error) => {
|
|
370
396
|
if (error instanceof Redirection) {
|
|
371
397
|
this.log.debug("Streaming resulted in redirection", {
|
|
@@ -382,7 +408,13 @@ export class ReactServerProvider {
|
|
|
382
408
|
|
|
383
409
|
this.log.trace("Page streaming started (early head optimization)");
|
|
384
410
|
route.onServerResponse?.(serverRequest);
|
|
385
|
-
reply.body = htmlStream
|
|
411
|
+
reply.body = htmlStream.pipeThrough(
|
|
412
|
+
new TransformStream({
|
|
413
|
+
flush: () => {
|
|
414
|
+
this.log.info("Page streaming completed", { name: route.name });
|
|
415
|
+
},
|
|
416
|
+
}),
|
|
417
|
+
);
|
|
386
418
|
};
|
|
387
419
|
}
|
|
388
420
|
|
|
@@ -567,6 +599,12 @@ declare module "alepha" {
|
|
|
567
599
|
/**
|
|
568
600
|
* React server provider configuration atom
|
|
569
601
|
*/
|
|
602
|
+
/**
|
|
603
|
+
* Default pattern matching file-like URLs (e.g. /hello.txt, /wp-login.php).
|
|
604
|
+
* Matches paths whose last segment contains a dot followed by 1-10 alphanumeric characters.
|
|
605
|
+
*/
|
|
606
|
+
export const DEFAULT_STATIC_FILE_PATTERN = "\\.[a-zA-Z0-9]{1,10}$";
|
|
607
|
+
|
|
570
608
|
export const reactServerOptions = $atom({
|
|
571
609
|
name: "alepha.react.server.options",
|
|
572
610
|
schema: t.object({
|
|
@@ -300,6 +300,7 @@ export class ReactServerTemplateProvider {
|
|
|
300
300
|
>,
|
|
301
301
|
options: {
|
|
302
302
|
hydration?: boolean;
|
|
303
|
+
state?: ReactRouterState;
|
|
303
304
|
onError?: (error: unknown) => void;
|
|
304
305
|
} = {},
|
|
305
306
|
): ReadableStream<Uint8Array> {
|
|
@@ -308,7 +309,7 @@ export class ReactServerTemplateProvider {
|
|
|
308
309
|
|
|
309
310
|
let headClosed = false;
|
|
310
311
|
let bodyStarted = false;
|
|
311
|
-
let routerState: ReactRouterState | undefined;
|
|
312
|
+
let routerState: ReactRouterState | undefined = options.state;
|
|
312
313
|
|
|
313
314
|
return new ReadableStream<Uint8Array>({
|
|
314
315
|
start: async (controller) => {
|
|
@@ -469,6 +470,17 @@ export class ReactServerTemplateProvider {
|
|
|
469
470
|
);
|
|
470
471
|
|
|
471
472
|
controller.enqueue(slots.ROOT_CLOSE);
|
|
473
|
+
|
|
474
|
+
if (routerState) {
|
|
475
|
+
controller.enqueue(slots.HYDRATION_PREFIX);
|
|
476
|
+
controller.enqueue(
|
|
477
|
+
encoder.encode(
|
|
478
|
+
this.safeJsonSerialize(this.buildHydrationData(routerState)),
|
|
479
|
+
),
|
|
480
|
+
);
|
|
481
|
+
controller.enqueue(slots.HYDRATION_SUFFIX);
|
|
482
|
+
}
|
|
483
|
+
|
|
472
484
|
controller.enqueue(slots.BODY_HTML_CLOSE);
|
|
473
485
|
}
|
|
474
486
|
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
$env,
|
|
3
2
|
$hook,
|
|
4
3
|
$inject,
|
|
5
4
|
Alepha,
|
|
6
5
|
AppNotStartedError,
|
|
7
6
|
ContainerLockedError,
|
|
8
|
-
type Static,
|
|
9
|
-
t,
|
|
10
7
|
} from "alepha";
|
|
8
|
+
import { SecretProvider } from "alepha/crypto";
|
|
11
9
|
import { $logger } from "alepha/logger";
|
|
12
10
|
import { ForbiddenError } from "alepha/server";
|
|
13
11
|
import type { JSONWebKeySet, JWTPayload } from "jose";
|
|
@@ -27,20 +25,6 @@ import {
|
|
|
27
25
|
} from "../schemas/userAccountInfoSchema.ts";
|
|
28
26
|
import { JwtProvider } from "./JwtProvider.ts";
|
|
29
27
|
|
|
30
|
-
export const DEFAULT_APP_SECRET = "05759934015388327323179852515731"; // (32)
|
|
31
|
-
|
|
32
|
-
export const alephaSecurityEnvSchema = t.object({
|
|
33
|
-
APP_SECRET: t.text({
|
|
34
|
-
description:
|
|
35
|
-
"The secret key used for signing JWTs and other security features. It should be a strong, random string of at least 32 characters for HS256. Do not use the default value in production.",
|
|
36
|
-
default: DEFAULT_APP_SECRET,
|
|
37
|
-
}),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
declare module "alepha" {
|
|
41
|
-
interface Env extends Partial<Static<typeof alephaSecurityEnvSchema>> {}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
28
|
export class SecurityProvider {
|
|
45
29
|
protected readonly UNKNOWN_USER_NAME = "Anonymous User";
|
|
46
30
|
protected readonly PERMISSION_REGEXP = /^[\w-]+((:[\w-]+)+)?$/;
|
|
@@ -49,11 +33,11 @@ export class SecurityProvider {
|
|
|
49
33
|
|
|
50
34
|
protected readonly log = $logger();
|
|
51
35
|
protected readonly jwt = $inject(JwtProvider);
|
|
52
|
-
protected readonly env = $env(alephaSecurityEnvSchema);
|
|
53
36
|
protected readonly alepha = $inject(Alepha);
|
|
37
|
+
protected readonly secretProvider = $inject(SecretProvider);
|
|
54
38
|
|
|
55
|
-
public get secretKey() {
|
|
56
|
-
return this.
|
|
39
|
+
public get secretKey(): string {
|
|
40
|
+
return this.secretProvider.secretKey;
|
|
57
41
|
}
|
|
58
42
|
|
|
59
43
|
/**
|
|
@@ -68,7 +52,7 @@ export class SecurityProvider {
|
|
|
68
52
|
? [
|
|
69
53
|
{
|
|
70
54
|
name: "default",
|
|
71
|
-
secret: this.
|
|
55
|
+
secret: this.secretKey,
|
|
72
56
|
roles: [
|
|
73
57
|
{
|
|
74
58
|
name: "admin",
|
|
@@ -86,12 +70,6 @@ export class SecurityProvider {
|
|
|
86
70
|
protected start = $hook({
|
|
87
71
|
on: "start",
|
|
88
72
|
handler: async () => {
|
|
89
|
-
if (this.alepha.isProduction() && this.secretKey === DEFAULT_APP_SECRET) {
|
|
90
|
-
this.log.warn(
|
|
91
|
-
"Using default APP_SECRET in production is not recommended. Please set a strong APP_SECRET value.",
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
73
|
for (const realm of this.realms) {
|
|
96
74
|
if (realm.secret) {
|
|
97
75
|
const secret =
|
|
@@ -255,7 +255,29 @@ export class AuthPrimitive extends Primitive<AuthPrimitiveOptions> {
|
|
|
255
255
|
protected readonly securityProvider = $inject(SecurityProvider);
|
|
256
256
|
protected readonly dateTimeProvider = $inject(DateTimeProvider);
|
|
257
257
|
|
|
258
|
-
|
|
258
|
+
protected oauthConfig?: Configuration;
|
|
259
|
+
protected oauthInitializer?: () => Promise<Configuration>;
|
|
260
|
+
|
|
261
|
+
public get oauth(): Configuration | undefined {
|
|
262
|
+
return this.oauthConfig;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get the OAuth2/OIDC configuration, initializing lazily if needed (serverless mode).
|
|
267
|
+
*/
|
|
268
|
+
public async getOAuth(): Promise<Configuration | undefined> {
|
|
269
|
+
if (this.oauthConfig) {
|
|
270
|
+
return this.oauthConfig;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (this.oauthInitializer) {
|
|
274
|
+
this.oauthConfig = await this.oauthInitializer();
|
|
275
|
+
this.oauthInitializer = undefined;
|
|
276
|
+
return this.oauthConfig;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
259
281
|
|
|
260
282
|
public get name() {
|
|
261
283
|
return this.options.name ?? this.config.propertyKey;
|
|
@@ -320,10 +342,13 @@ export class AuthPrimitive extends Primitive<AuthPrimitiveOptions> {
|
|
|
320
342
|
},
|
|
321
343
|
);
|
|
322
344
|
});
|
|
323
|
-
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const oauth = await this.getOAuth();
|
|
348
|
+
if (oauth) {
|
|
324
349
|
try {
|
|
325
350
|
return {
|
|
326
|
-
...(await refreshTokenGrant(
|
|
351
|
+
...(await refreshTokenGrant(oauth, refreshToken)),
|
|
327
352
|
issued_at: this.dateTimeProvider.now().unix(),
|
|
328
353
|
};
|
|
329
354
|
} catch (error) {
|
|
@@ -399,30 +424,38 @@ export class AuthPrimitive extends Primitive<AuthPrimitiveOptions> {
|
|
|
399
424
|
}
|
|
400
425
|
|
|
401
426
|
public async prepare() {
|
|
402
|
-
const addons: Array<(config: Configuration) => void> = [];
|
|
403
|
-
|
|
404
|
-
addons.push(allowInsecureRequests);
|
|
405
|
-
|
|
406
427
|
if ("oidc" in this.options) {
|
|
407
428
|
const { oidc } = this.options;
|
|
408
429
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
430
|
+
const discoverOidc = async () => {
|
|
431
|
+
const execute: Array<(config: Configuration) => void> = [];
|
|
432
|
+
execute.push(allowInsecureRequests);
|
|
433
|
+
|
|
434
|
+
return discovery(
|
|
435
|
+
new URL(oidc.issuer),
|
|
436
|
+
oidc.clientId,
|
|
437
|
+
{
|
|
438
|
+
client_secret: oidc.clientSecret,
|
|
439
|
+
},
|
|
440
|
+
undefined,
|
|
441
|
+
{
|
|
442
|
+
execute,
|
|
443
|
+
},
|
|
444
|
+
);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
// Defer OIDC discovery in serverless/dev to avoid cold start penalty
|
|
448
|
+
if (this.alepha.isServerless() || !this.alepha.isProduction()) {
|
|
449
|
+
this.oauthInitializer = discoverOidc;
|
|
450
|
+
} else {
|
|
451
|
+
this.oauthConfig = await discoverOidc();
|
|
452
|
+
}
|
|
420
453
|
}
|
|
421
454
|
|
|
422
455
|
if ("oauth" in this.options) {
|
|
423
456
|
const { oauth } = this.options;
|
|
424
457
|
|
|
425
|
-
this.
|
|
458
|
+
this.oauthConfig = new Configuration(
|
|
426
459
|
{
|
|
427
460
|
authorization_endpoint: oauth.authorization,
|
|
428
461
|
token_endpoint: oauth.token,
|