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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $module, type Alepha
|
|
2
|
-
import { AlephaOrm, DatabaseProvider } from "alepha/orm";
|
|
1
|
+
import { $module, type Alepha } from "alepha";
|
|
2
|
+
import { AlephaOrm, DatabaseProvider, databaseEnvSchema } from "alepha/orm";
|
|
3
3
|
import { BunPostgresProvider } from "./providers/BunPostgresProvider.ts";
|
|
4
4
|
import { CloudflareHyperdriveProvider } from "./providers/CloudflareHyperdriveProvider.ts";
|
|
5
5
|
import { NodePostgresProvider } from "./providers/NodePostgresProvider.ts";
|
|
@@ -14,6 +14,7 @@ export * from "./providers/CloudflareHyperdriveProvider.ts";
|
|
|
14
14
|
export * from "./providers/NodePostgresProvider.ts";
|
|
15
15
|
export * from "./providers/PglitePostgresProvider.ts";
|
|
16
16
|
export * from "./providers/PostgresProvider.ts";
|
|
17
|
+
export * from "./schemas/postgresEnvSchema.ts";
|
|
17
18
|
export * from "./services/PostgresModelBuilder.ts";
|
|
18
19
|
export * from "./types/byte.ts";
|
|
19
20
|
|
|
@@ -31,11 +32,7 @@ export const AlephaOrmPostgres = $module({
|
|
|
31
32
|
PostgresModelBuilder,
|
|
32
33
|
],
|
|
33
34
|
register: (alepha: Alepha) => {
|
|
34
|
-
const env = alepha.parseEnv(
|
|
35
|
-
t.object({
|
|
36
|
-
DATABASE_URL: t.optional(t.text()),
|
|
37
|
-
}),
|
|
38
|
-
);
|
|
35
|
+
const env = alepha.parseEnv(databaseEnvSchema);
|
|
39
36
|
|
|
40
37
|
const url = env.DATABASE_URL;
|
|
41
38
|
const isBun = alepha.isBun();
|
|
@@ -66,8 +66,18 @@ export class BunPostgresProvider extends PostgresProvider {
|
|
|
66
66
|
|
|
67
67
|
const { drizzle } = await import("drizzle-orm/bun-sql");
|
|
68
68
|
|
|
69
|
-
// Create Bun SQL client
|
|
70
|
-
|
|
69
|
+
// Create Bun SQL client with pool options
|
|
70
|
+
const bunOptions: Record<string, any> = { url: this.url };
|
|
71
|
+
if (this.pgEnv.POOL_MAX != null) {
|
|
72
|
+
bunOptions.max = this.pgEnv.POOL_MAX;
|
|
73
|
+
}
|
|
74
|
+
if (this.pgEnv.POOL_IDLE_TIMEOUT != null) {
|
|
75
|
+
bunOptions.idleTimeout = this.pgEnv.POOL_IDLE_TIMEOUT;
|
|
76
|
+
}
|
|
77
|
+
if (this.pgEnv.POOL_CONNECT_TIMEOUT != null) {
|
|
78
|
+
bunOptions.connectionTimeout = this.pgEnv.POOL_CONNECT_TIMEOUT;
|
|
79
|
+
}
|
|
80
|
+
this.client = new Bun.SQL(bunOptions);
|
|
71
81
|
|
|
72
82
|
// Test connection
|
|
73
83
|
await this.client.unsafe("SELECT 1");
|
|
@@ -104,6 +104,13 @@ export class NodePostgresProvider extends PostgresProvider {
|
|
|
104
104
|
},
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
+
// Pool options — only set when explicitly configured via env vars
|
|
108
|
+
if (this.pgEnv.POOL_MAX != null) options.max = this.pgEnv.POOL_MAX;
|
|
109
|
+
if (this.pgEnv.POOL_IDLE_TIMEOUT != null)
|
|
110
|
+
options.idle_timeout = this.pgEnv.POOL_IDLE_TIMEOUT;
|
|
111
|
+
if (this.pgEnv.POOL_CONNECT_TIMEOUT != null)
|
|
112
|
+
options.connect_timeout = this.pgEnv.POOL_CONNECT_TIMEOUT;
|
|
113
|
+
|
|
107
114
|
// Set search_path at connection level so schema-free migration SQL
|
|
108
115
|
// resolves to the correct PostgreSQL schema across all pool connections.
|
|
109
116
|
if (this.schema !== "public") {
|
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
import { mkdir } from "node:fs/promises";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import type { PGlite } from "@electric-sql/pglite";
|
|
4
|
-
import { $env, $hook, $inject, AlephaError
|
|
5
|
-
import { DatabaseProvider, type SQLLike } from "alepha/orm";
|
|
4
|
+
import { $env, $hook, $inject, AlephaError } from "alepha";
|
|
5
|
+
import { DatabaseProvider, databaseEnvSchema, type SQLLike } from "alepha/orm";
|
|
6
6
|
import { sql } from "drizzle-orm";
|
|
7
7
|
import type { PgliteDatabase } from "drizzle-orm/pglite";
|
|
8
8
|
import { migrate } from "drizzle-orm/pglite/migrator";
|
|
9
|
+
import { postgresEnvSchema } from "../schemas/postgresEnvSchema.ts";
|
|
9
10
|
import { PostgresModelBuilder } from "../services/PostgresModelBuilder.ts";
|
|
10
11
|
|
|
11
|
-
const envSchema = t.object({
|
|
12
|
-
/**
|
|
13
|
-
* Same as NodePostgresProvider connection string.
|
|
14
|
-
* But, will accept only `file:` protocol for the database path.
|
|
15
|
-
*
|
|
16
|
-
* DATABASE_URL=memory://
|
|
17
|
-
* DATABASE_URL=./db
|
|
18
|
-
* DATABASE_URL=file://absolute/path/to/db
|
|
19
|
-
*/
|
|
20
|
-
DATABASE_URL: t.optional(t.text()),
|
|
21
|
-
POSTGRES_SCHEMA: t.optional(t.text()),
|
|
22
|
-
});
|
|
23
|
-
|
|
24
12
|
export interface PgLiteModule {
|
|
25
13
|
PGlite: typeof PGlite;
|
|
26
14
|
}
|
|
@@ -35,10 +23,11 @@ export class PglitePostgresProvider extends DatabaseProvider {
|
|
|
35
23
|
}
|
|
36
24
|
|
|
37
25
|
public override get schema(): string {
|
|
38
|
-
return this.
|
|
26
|
+
return this.pgEnv.POSTGRES_SCHEMA ?? "public";
|
|
39
27
|
}
|
|
40
28
|
|
|
41
|
-
protected readonly env = $env(
|
|
29
|
+
protected readonly env = $env(databaseEnvSchema);
|
|
30
|
+
protected readonly pgEnv = $env(postgresEnvSchema);
|
|
42
31
|
protected readonly builder = $inject(PostgresModelBuilder);
|
|
43
32
|
|
|
44
33
|
protected client?: PGlite;
|
|
@@ -54,6 +43,10 @@ export class PglitePostgresProvider extends DatabaseProvider {
|
|
|
54
43
|
|
|
55
44
|
public override readonly dialect = "postgresql";
|
|
56
45
|
|
|
46
|
+
public override get supportsTransactions(): boolean {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
57
50
|
public override get url(): string {
|
|
58
51
|
let path = this.env.DATABASE_URL;
|
|
59
52
|
|
|
@@ -1,49 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
$env,
|
|
3
|
-
$hook,
|
|
4
|
-
$inject,
|
|
5
|
-
$pipeline,
|
|
6
|
-
AlephaError,
|
|
7
|
-
type Static,
|
|
8
|
-
t,
|
|
9
|
-
} from "alepha";
|
|
1
|
+
import { $env, $hook, $inject, $pipeline, AlephaError } from "alepha";
|
|
10
2
|
import { $lock } from "alepha/lock";
|
|
11
3
|
import {
|
|
12
4
|
DatabaseProvider,
|
|
13
5
|
DbError,
|
|
14
6
|
DbMigrationError,
|
|
7
|
+
databaseEnvSchema,
|
|
15
8
|
type SQLLike,
|
|
16
9
|
} from "alepha/orm";
|
|
17
10
|
import { sql } from "drizzle-orm";
|
|
18
11
|
import type { PgDatabase } from "drizzle-orm/pg-core";
|
|
12
|
+
import { postgresEnvSchema } from "../schemas/postgresEnvSchema.ts";
|
|
19
13
|
import { PostgresModelBuilder } from "../services/PostgresModelBuilder.ts";
|
|
20
14
|
|
|
21
15
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
22
16
|
|
|
23
|
-
const envSchema = t.object({
|
|
24
|
-
/**
|
|
25
|
-
* Main configuration for database connection.
|
|
26
|
-
* Accept a string in the format of a Postgres connection URL.
|
|
27
|
-
* Example: postgres://user:password@localhost:5432/database
|
|
28
|
-
* or
|
|
29
|
-
* Example: postgres://user:password@localhost:5432/database?sslmode=require
|
|
30
|
-
*/
|
|
31
|
-
DATABASE_URL: t.optional(t.text()),
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* In addition to the DATABASE_URL, you can specify the postgres schema name.
|
|
35
|
-
*
|
|
36
|
-
* It will monkey patch drizzle tables.
|
|
37
|
-
*/
|
|
38
|
-
POSTGRES_SCHEMA: t.optional(t.text()),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
declare module "alepha" {
|
|
42
|
-
interface Env extends Partial<Static<typeof envSchema>> {}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ---------------------------------------------------------------------------------------------------------------------
|
|
46
|
-
|
|
47
17
|
/**
|
|
48
18
|
* Abstract base class for PostgreSQL database providers.
|
|
49
19
|
*
|
|
@@ -56,7 +26,8 @@ declare module "alepha" {
|
|
|
56
26
|
* Subclasses must implement `connect()`, `close()`, and `executeMigrations()`.
|
|
57
27
|
*/
|
|
58
28
|
export abstract class PostgresProvider extends DatabaseProvider {
|
|
59
|
-
protected readonly env = $env(
|
|
29
|
+
protected readonly env = $env(databaseEnvSchema);
|
|
30
|
+
protected readonly pgEnv = $env(postgresEnvSchema);
|
|
60
31
|
protected readonly builder = $inject(PostgresModelBuilder);
|
|
61
32
|
|
|
62
33
|
public override readonly dialect = "postgresql";
|
|
@@ -101,8 +72,8 @@ export abstract class PostgresProvider extends DatabaseProvider {
|
|
|
101
72
|
return this.schemaForTesting;
|
|
102
73
|
}
|
|
103
74
|
|
|
104
|
-
if (this.
|
|
105
|
-
return this.
|
|
75
|
+
if (this.pgEnv.POSTGRES_SCHEMA) {
|
|
76
|
+
return this.pgEnv.POSTGRES_SCHEMA;
|
|
106
77
|
}
|
|
107
78
|
|
|
108
79
|
return "public";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Static, t } from "alepha";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PostgreSQL-specific environment schema.
|
|
5
|
+
*
|
|
6
|
+
* Additional env vars for PostgreSQL providers on top of `databaseEnvSchema`.
|
|
7
|
+
*/
|
|
8
|
+
export const postgresEnvSchema = t.object({
|
|
9
|
+
/**
|
|
10
|
+
* PostgreSQL schema name (defaults to `"public"` when unset).
|
|
11
|
+
*/
|
|
12
|
+
POSTGRES_SCHEMA: t.optional(t.text()),
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Maximum number of connections in the pool.
|
|
16
|
+
*/
|
|
17
|
+
POOL_MAX: t.optional(t.integer()),
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Seconds a connection can be idle before being closed.
|
|
21
|
+
*/
|
|
22
|
+
POOL_IDLE_TIMEOUT: t.optional(t.integer()),
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Seconds to wait when establishing a new connection.
|
|
26
|
+
*/
|
|
27
|
+
POOL_CONNECT_TIMEOUT: t.optional(t.integer()),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
declare module "alepha" {
|
|
31
|
+
interface Env extends Partial<Static<typeof postgresEnvSchema>> {}
|
|
32
|
+
}
|
|
@@ -5,16 +5,19 @@ import {
|
|
|
5
5
|
ModelBuilder,
|
|
6
6
|
PG_CREATED_AT,
|
|
7
7
|
PG_ENUM,
|
|
8
|
+
PG_GENERATED,
|
|
8
9
|
PG_IDENTITY,
|
|
9
10
|
PG_PRIMARY_KEY,
|
|
10
11
|
PG_REF,
|
|
11
12
|
PG_SERIAL,
|
|
12
13
|
PG_UPDATED_AT,
|
|
13
14
|
type PgEnumOptions,
|
|
15
|
+
type PgGeneratedOptions,
|
|
14
16
|
type PgIdentityOptions,
|
|
15
17
|
type PgRefOptions,
|
|
16
18
|
type SequencePrimitive,
|
|
17
19
|
schema,
|
|
20
|
+
type ViewPrimitive,
|
|
18
21
|
} from "alepha/orm";
|
|
19
22
|
import type { BuildExtraConfigColumns } from "drizzle-orm";
|
|
20
23
|
import * as pg from "drizzle-orm/pg-core";
|
|
@@ -27,9 +30,11 @@ import {
|
|
|
27
30
|
type PgTableExtraConfigValue,
|
|
28
31
|
type PgTableWithColumns,
|
|
29
32
|
pgEnum,
|
|
33
|
+
pgMaterializedView,
|
|
30
34
|
pgSchema,
|
|
31
35
|
pgSequence,
|
|
32
36
|
pgTable,
|
|
37
|
+
pgView,
|
|
33
38
|
unique,
|
|
34
39
|
uniqueIndex,
|
|
35
40
|
} from "drizzle-orm/pg-core";
|
|
@@ -97,6 +102,36 @@ export class PostgresModelBuilder extends ModelBuilder {
|
|
|
97
102
|
options.tables.set(tableName, table);
|
|
98
103
|
}
|
|
99
104
|
|
|
105
|
+
public buildView(
|
|
106
|
+
view: ViewPrimitive,
|
|
107
|
+
options: {
|
|
108
|
+
tables: Map<string, unknown>;
|
|
109
|
+
schema: string;
|
|
110
|
+
},
|
|
111
|
+
) {
|
|
112
|
+
const viewName = view.name;
|
|
113
|
+
if (options.tables.has(viewName)) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const columns = this.schemaToPgColumns(
|
|
118
|
+
viewName,
|
|
119
|
+
view.schema,
|
|
120
|
+
{ enum: pgEnum, table: pgTable, sequence: pgSequence } as any,
|
|
121
|
+
new Map(),
|
|
122
|
+
options.tables,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
let drizzleView: unknown;
|
|
126
|
+
if (view.materialized) {
|
|
127
|
+
drizzleView = pgMaterializedView(viewName, columns).existing();
|
|
128
|
+
} else {
|
|
129
|
+
drizzleView = pgView(viewName, columns).existing();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
options.tables.set(viewName, drizzleView);
|
|
133
|
+
}
|
|
134
|
+
|
|
100
135
|
public buildSequence(
|
|
101
136
|
sequence: SequencePrimitive,
|
|
102
137
|
options: {
|
|
@@ -194,6 +229,11 @@ export class PostgresModelBuilder extends ModelBuilder {
|
|
|
194
229
|
}, config.actions);
|
|
195
230
|
}
|
|
196
231
|
|
|
232
|
+
if (PG_GENERATED in value) {
|
|
233
|
+
const gen = value[PG_GENERATED] as PgGeneratedOptions;
|
|
234
|
+
col = col.generatedAlwaysAs(gen.expression);
|
|
235
|
+
}
|
|
236
|
+
|
|
197
237
|
if (schema.required?.includes(key)) {
|
|
198
238
|
col = col.notNull();
|
|
199
239
|
}
|
|
@@ -12,7 +12,7 @@ export interface ErrorBoundaryProps {
|
|
|
12
12
|
* Fallback React node to render when an error is caught.
|
|
13
13
|
* If not provided, a default error message will be shown.
|
|
14
14
|
*/
|
|
15
|
-
fallback: (error: Error) => ReactNode;
|
|
15
|
+
fallback: (error: Error, reset: () => void) => ReactNode;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Optional callback that receives the error and error info.
|
|
@@ -63,7 +63,10 @@ export class ErrorBoundary extends React.Component<
|
|
|
63
63
|
|
|
64
64
|
render(): ReactNode {
|
|
65
65
|
if (this.state.error) {
|
|
66
|
-
|
|
66
|
+
const reset = () => {
|
|
67
|
+
this.setState({ error: undefined });
|
|
68
|
+
};
|
|
69
|
+
return this.props.fallback(this.state.error, reset);
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
return this.props.children;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useAlepha } from "alepha/react";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import type { BaseInputField } from "../services/FormModel.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to subscribe to a single form field's value.
|
|
7
|
+
* Only re-renders when this specific field changes.
|
|
8
|
+
*
|
|
9
|
+
* @returns A tuple of [value, setValue] similar to useState.
|
|
10
|
+
*/
|
|
11
|
+
export const useFieldValue = (
|
|
12
|
+
input: BaseInputField,
|
|
13
|
+
): [any, (value: any) => void] => {
|
|
14
|
+
const alepha = useAlepha();
|
|
15
|
+
const [value, setValue] = useState(input?.initialValue);
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!input?.form || !alepha.isBrowser()) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return alepha.events.on("form:change", (ev) => {
|
|
23
|
+
if (ev.id === input.form.id && ev.path === input.path) {
|
|
24
|
+
setValue(ev.value);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
const setFieldValue = (newValue: any) => {
|
|
30
|
+
input.set(newValue);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return [value, setFieldValue];
|
|
34
|
+
};
|
|
@@ -3,8 +3,20 @@ import { Alepha, t } from "alepha";
|
|
|
3
3
|
import { AlephaLogger } from "alepha/logger";
|
|
4
4
|
import { AlephaContext } from "alepha/react";
|
|
5
5
|
import type { ReactNode } from "react";
|
|
6
|
+
import { useState } from "react";
|
|
6
7
|
import { describe, it } from "vitest";
|
|
7
|
-
import { useForm } from "../index.ts";
|
|
8
|
+
import { useFieldValue, useForm } from "../index.ts";
|
|
9
|
+
|
|
10
|
+
const TestInput = ({ input, testId }: { input: any; testId: string }) => {
|
|
11
|
+
const [value, setValue] = useFieldValue(input);
|
|
12
|
+
return (
|
|
13
|
+
<input
|
|
14
|
+
data-testid={testId}
|
|
15
|
+
value={value ?? ""}
|
|
16
|
+
onChange={(ev) => setValue(ev.target.value)}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
8
20
|
|
|
9
21
|
describe("useForm", () => {
|
|
10
22
|
const renderWithAlepha = (alepha: Alepha, element: ReactNode) => {
|
|
@@ -29,17 +41,23 @@ describe("useForm", () => {
|
|
|
29
41
|
}),
|
|
30
42
|
}),
|
|
31
43
|
}),
|
|
32
|
-
handler: (values
|
|
44
|
+
handler: (values) => {
|
|
33
45
|
calls.push(values);
|
|
34
46
|
},
|
|
35
47
|
});
|
|
36
48
|
|
|
37
49
|
return (
|
|
38
50
|
<form {...form.props} data-testid="test-form">
|
|
39
|
-
<input
|
|
40
|
-
<input
|
|
41
|
-
<
|
|
42
|
-
|
|
51
|
+
<TestInput input={form.input.str} testId="test-str" />
|
|
52
|
+
<TestInput input={form.input.int} testId="test-int" />
|
|
53
|
+
<TestInput
|
|
54
|
+
input={form.input.nested.items.str}
|
|
55
|
+
testId="test-nested.str"
|
|
56
|
+
/>
|
|
57
|
+
<TestInput
|
|
58
|
+
input={form.input.nested.items.another.items.level}
|
|
59
|
+
testId="test-nested.another.level"
|
|
60
|
+
/>
|
|
43
61
|
<button type="submit">Submit</button>
|
|
44
62
|
</form>
|
|
45
63
|
);
|
|
@@ -312,9 +330,18 @@ describe("useForm", () => {
|
|
|
312
330
|
|
|
313
331
|
return (
|
|
314
332
|
<form {...form.props} data-testid="complex-form">
|
|
315
|
-
<
|
|
316
|
-
|
|
317
|
-
|
|
333
|
+
<TestInput
|
|
334
|
+
input={form.input.company.items.name}
|
|
335
|
+
testId="complex-test-company.name"
|
|
336
|
+
/>
|
|
337
|
+
<TestInput
|
|
338
|
+
input={form.input.company.items.address.items.street}
|
|
339
|
+
testId="complex-test-company.address.street"
|
|
340
|
+
/>
|
|
341
|
+
<TestInput
|
|
342
|
+
input={form.input.company.items.address.items.city}
|
|
343
|
+
testId="complex-test-company.address.city"
|
|
344
|
+
/>
|
|
318
345
|
<button
|
|
319
346
|
type="button"
|
|
320
347
|
data-testid="set-employees"
|
|
@@ -363,4 +390,62 @@ describe("useForm", () => {
|
|
|
363
390
|
],
|
|
364
391
|
});
|
|
365
392
|
});
|
|
393
|
+
|
|
394
|
+
it("should update initialValues after save so reset uses new values", async ({
|
|
395
|
+
expect,
|
|
396
|
+
}) => {
|
|
397
|
+
const alepha = Alepha.create().with(AlephaLogger);
|
|
398
|
+
|
|
399
|
+
const Form = () => {
|
|
400
|
+
const [saved, setSaved] = useState({ name: "original" });
|
|
401
|
+
|
|
402
|
+
const form = useForm({
|
|
403
|
+
id: "reset-test",
|
|
404
|
+
schema: t.object({
|
|
405
|
+
name: t.text(),
|
|
406
|
+
}),
|
|
407
|
+
initialValues: saved,
|
|
408
|
+
handler: async (values) => {
|
|
409
|
+
setSaved({ ...values });
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<form {...form.props} data-testid="reset-form">
|
|
415
|
+
<TestInput input={form.input.name} testId="reset-name" />
|
|
416
|
+
<button type="submit">Save</button>
|
|
417
|
+
<button type="reset">Reset</button>
|
|
418
|
+
</form>
|
|
419
|
+
);
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
await alepha.start();
|
|
423
|
+
const ui = renderWithAlepha(alepha, <Form />);
|
|
424
|
+
|
|
425
|
+
const input = () =>
|
|
426
|
+
(ui.getByTestId("reset-name") as HTMLInputElement).value;
|
|
427
|
+
|
|
428
|
+
// Initial value
|
|
429
|
+
expect(input()).toBe("original");
|
|
430
|
+
|
|
431
|
+
// Edit and save
|
|
432
|
+
fireEvent.change(ui.getByTestId("reset-name"), {
|
|
433
|
+
target: { value: "updated" },
|
|
434
|
+
});
|
|
435
|
+
fireEvent.submit(ui.getByText("Save"));
|
|
436
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
437
|
+
|
|
438
|
+
// After save, initialValues should be updated
|
|
439
|
+
// Edit again
|
|
440
|
+
fireEvent.change(ui.getByTestId("reset-name"), {
|
|
441
|
+
target: { value: "temporary" },
|
|
442
|
+
});
|
|
443
|
+
expect(input()).toBe("temporary");
|
|
444
|
+
|
|
445
|
+
// Reset should go back to saved value, not original
|
|
446
|
+
fireEvent.click(ui.getByText("Reset"));
|
|
447
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
448
|
+
|
|
449
|
+
expect(input()).toBe("updated");
|
|
450
|
+
});
|
|
366
451
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TObject } from "alepha";
|
|
2
2
|
import { useAlepha } from "alepha/react";
|
|
3
|
-
import { useId, useMemo } from "react";
|
|
3
|
+
import { useEffect, useId, useMemo, useRef } from "react";
|
|
4
4
|
import { type FormCtrlOptions, FormModel } from "../services/FormModel.ts";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -37,11 +37,23 @@ export const useForm = <T extends TObject>(
|
|
|
37
37
|
): FormModel<T> => {
|
|
38
38
|
const alepha = useAlepha();
|
|
39
39
|
const formId = useId();
|
|
40
|
+
const initialValuesRef = useRef(options.initialValues);
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
const form = useMemo(() => {
|
|
42
43
|
return alepha.inject(FormModel<T>, {
|
|
43
44
|
lifetime: "transient",
|
|
44
45
|
args: [options.id || formId, options],
|
|
45
46
|
});
|
|
46
47
|
}, deps);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (initialValuesRef.current !== options.initialValues) {
|
|
51
|
+
initialValuesRef.current = options.initialValues;
|
|
52
|
+
if (options.initialValues) {
|
|
53
|
+
form.setInitialValues(options.initialValues as Record<string, any>);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, [options.initialValues]);
|
|
57
|
+
|
|
58
|
+
return form;
|
|
47
59
|
};
|
|
@@ -58,16 +58,6 @@ export const useFormState = <
|
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (hasValues) {
|
|
62
|
-
listeners.push(
|
|
63
|
-
alepha.events.on("form:reset", (event) => {
|
|
64
|
-
if (event.id === form.id) {
|
|
65
|
-
setValues(event.values);
|
|
66
|
-
}
|
|
67
|
-
}),
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
61
|
if (hasLoading) {
|
|
72
62
|
listeners.push(
|
|
73
63
|
alepha.events.on("form:submit:begin", (event) => {
|
|
@@ -98,6 +88,16 @@ export const useFormState = <
|
|
|
98
88
|
);
|
|
99
89
|
}
|
|
100
90
|
|
|
91
|
+
if (hasDirty) {
|
|
92
|
+
listeners.push(
|
|
93
|
+
alepha.events.on("form:reset", (event) => {
|
|
94
|
+
if (event.id === form.id) {
|
|
95
|
+
setDirty(false);
|
|
96
|
+
}
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
101
|
if (hasErrors) {
|
|
102
102
|
listeners.push(
|
|
103
103
|
alepha.events.on("form:submit:error", (event) => {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TObject } from "alepha";
|
|
2
|
+
import { useAlepha } from "alepha/react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import type { FormModel } from "../services/FormModel.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Hook to subscribe to all form values.
|
|
8
|
+
* Re-renders on every field change — use only when needed (debug panels, live previews).
|
|
9
|
+
*/
|
|
10
|
+
export const useFormValues = <T extends TObject>(
|
|
11
|
+
form: FormModel<T>,
|
|
12
|
+
): Record<string, any> => {
|
|
13
|
+
const alepha = useAlepha();
|
|
14
|
+
const [values, setValues] = useState<Record<string, any>>(form.currentValues);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!alepha.isBrowser()) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return alepha.events.on("form:change", (ev) => {
|
|
22
|
+
if (ev.id === form.id) {
|
|
23
|
+
setValues(form.currentValues);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
return values;
|
|
29
|
+
};
|
package/src/react/form/index.ts
CHANGED
|
@@ -4,8 +4,10 @@ import { $module } from "alepha";
|
|
|
4
4
|
|
|
5
5
|
export { default as FormState } from "./components/FormState.tsx";
|
|
6
6
|
export * from "./errors/FormValidationError.ts";
|
|
7
|
+
export * from "./hooks/useFieldValue.ts";
|
|
7
8
|
export * from "./hooks/useForm.ts";
|
|
8
9
|
export * from "./hooks/useFormState.ts";
|
|
10
|
+
export * from "./hooks/useFormValues.ts";
|
|
9
11
|
export * from "./services/FormModel.ts";
|
|
10
12
|
|
|
11
13
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
@@ -13,11 +15,11 @@ export * from "./services/FormModel.ts";
|
|
|
13
15
|
declare module "alepha" {
|
|
14
16
|
interface Hooks {
|
|
15
17
|
"form:change": { id: string; path: string; value: any };
|
|
16
|
-
"form:reset": { id: string; values: Record<string, any> };
|
|
17
18
|
"form:submit:begin": { id: string };
|
|
18
19
|
"form:submit:success": { id: string; values: Record<string, any> };
|
|
19
20
|
"form:submit:error": { id: string; error: Error };
|
|
20
21
|
"form:submit:end": { id: string };
|
|
22
|
+
"form:reset": { id: string };
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|