@podosoft/podokit 1.4.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/app-proxy-timeouts.d.ts +27 -0
- package/dist/app-proxy-timeouts.js +180 -0
- package/dist/assemble.d.ts +5 -2
- package/dist/assemble.js +14 -4
- package/dist/deploy-checks.d.ts +44 -0
- package/dist/deploy-checks.js +267 -0
- package/dist/deploy-compose-profile.d.ts +6 -2
- package/dist/deploy-compose-profile.js +15 -6
- package/dist/deploy-compose-render.d.ts +12 -4
- package/dist/deploy-compose-render.js +47 -17
- package/dist/deploy-compose.d.ts +2 -5
- package/dist/deploy-compose.js +7 -2
- package/dist/deploy-profile.d.ts +6 -2
- package/dist/deploy-profile.js +11 -7
- package/dist/deploy-render.d.ts +4 -1
- package/dist/deploy-render.js +28 -20
- package/dist/deploy-schema.d.ts +61 -0
- package/dist/deploy-schema.js +157 -1
- package/dist/deploy.d.ts +2 -5
- package/dist/deploy.js +5 -2
- package/dist/dev.d.ts +21 -0
- package/dist/dev.js +78 -3
- package/dist/eject.js +2 -0
- package/dist/index.js +85 -5
- package/dist/lib.d.ts +2 -0
- package/dist/lib.js +5 -2
- package/dist/lockfile.d.ts +24 -0
- package/dist/lockfile.js +77 -5
- package/dist/provider.d.ts +1 -0
- package/dist/provider.js +12 -4
- package/dist/remove.js +1 -1
- package/dist/template-files.d.ts +42 -0
- package/dist/template-files.js +102 -0
- package/dist/templates/fullstack/AGENTS.md +44 -7
- package/dist/templates/fullstack/README.md +8 -7
- package/dist/templates/fullstack/apps/api/package.json +4 -4
- package/dist/templates/fullstack/apps/api/scripts/build.extensions.mjs +6 -0
- package/dist/templates/fullstack/apps/api/scripts/build.mjs +65 -16
- package/dist/templates/fullstack/apps/api/scripts/run-migrations.mjs +7 -3
- package/dist/templates/fullstack/apps/api/scripts/verify-api-contract.ts +5 -1
- package/dist/templates/fullstack/apps/api/src/app.extensions.ts +7 -4
- package/dist/templates/fullstack/apps/api/src/app.spec.ts +22 -0
- package/dist/templates/fullstack/apps/api/src/app.ts +47 -28
- package/dist/templates/fullstack/apps/api/src/build.spec.ts +118 -0
- package/dist/templates/fullstack/apps/api/src/config/env.extensions.ts +20 -0
- package/dist/templates/fullstack/apps/api/src/config/env.validation.spec.ts +76 -0
- package/dist/templates/fullstack/apps/api/src/config/env.validation.ts +46 -3
- package/dist/templates/fullstack/apps/api/src/config/provider-selection.spec.ts +53 -0
- package/dist/templates/fullstack/apps/api/src/config/provider-selection.ts +79 -0
- package/dist/templates/fullstack/apps/api/src/config/providers.ts +8 -2
- package/dist/templates/fullstack/apps/api/src/config/server-options.spec.ts +17 -6
- package/dist/templates/fullstack/apps/api/src/config/server-options.ts +5 -8
- package/dist/templates/fullstack/apps/api/src/core/api-contract.extensions.ts +6 -0
- package/dist/templates/fullstack/apps/api/src/core/api-contract.spec.ts +29 -0
- package/dist/templates/fullstack/apps/api/src/core/api-contract.ts +39 -2
- package/dist/templates/fullstack/apps/api/src/core/client-address.spec.ts +82 -0
- package/dist/templates/fullstack/apps/api/src/core/client-address.ts +68 -0
- package/dist/templates/fullstack/apps/api/src/core/services.ts +43 -0
- package/dist/templates/fullstack/apps/api/src/database/data-source.spec.ts +27 -0
- package/dist/templates/fullstack/apps/api/src/database/data-source.ts +7 -10
- package/dist/templates/fullstack/apps/api/src/database/database.spec.ts +12 -0
- package/dist/templates/fullstack/apps/api/src/database/database.ts +2 -3
- package/dist/templates/fullstack/apps/api/src/database/entities.ts +12 -0
- package/dist/templates/fullstack/apps/api/src/database/migrate.ts +12 -2
- package/dist/templates/fullstack/apps/api/src/database/migration-files.spec.ts +116 -0
- package/dist/templates/fullstack/apps/api/src/database/migration-files.ts +134 -0
- package/dist/templates/fullstack/apps/api/src/database/migration-readiness.spec.ts +36 -0
- package/dist/templates/fullstack/apps/api/src/database/migration-readiness.ts +25 -0
- package/dist/templates/fullstack/apps/api/src/database/run-migrations.spec.ts +12 -1
- package/dist/templates/fullstack/apps/api/src/database/sqlite-migrator.ts +2 -36
- package/dist/templates/fullstack/apps/api/src/main.ts +2 -2
- package/dist/templates/fullstack/apps/api/tsconfig.json +2 -0
- package/dist/templates/fullstack/apps/web/Dockerfile +4 -0
- package/dist/templates/fullstack/apps/web/package.json +1 -1
- package/dist/templates/fullstack/apps/web/src/app.css +3 -0
- package/dist/templates/fullstack/apps/web/src/app.extensions.css +11 -0
- package/dist/templates/fullstack/apps/web/src/lib/components/site-runtime.svelte +3 -1
- package/dist/templates/fullstack/apps/web/src/lib/server/api.test.ts +19 -0
- package/dist/templates/fullstack/apps/web/src/lib/server/api.ts +4 -1
- package/dist/templates/fullstack/apps/web/src/lib/server/backend-proxy.test.ts +370 -36
- package/dist/templates/fullstack/apps/web/src/lib/server/backend-proxy.ts +250 -41
- package/dist/templates/fullstack/apps/web/src/lib/server/body-limits.ts +5 -2
- package/dist/templates/fullstack/apps/web/src/lib/server/proxy-timeouts.ts +23 -0
- package/dist/templates/fullstack/apps/web/tsconfig.json +1 -1
- package/dist/templates/fullstack/apps/web/vite.config.test.ts +33 -0
- package/dist/templates/fullstack/apps/web/vite.config.ts +55 -13
- package/dist/templates/fullstack/apps/web/vite.extensions.ts +23 -0
- package/dist/templates/fullstack/compose.dev.yaml +7 -4
- package/dist/templates/fullstack/dot-agents/skills/podokit-deploy/SKILL.md +2 -2
- package/dist/templates/fullstack/dot-agents/skills/podokit-deploy/references/profile.md +12 -3
- package/dist/templates/fullstack/dot-claude/skills/podokit-update/SKILL.md +5 -2
- package/dist/templates/fullstack/dot-env.docker.example +7 -2
- package/dist/templates/fullstack/dot-env.example +21 -1
- package/dist/templates/fullstack/dot-podokit/dev.json +1 -1
- package/dist/templates/fullstack/infra/k3s/configmap.yaml +4 -0
- package/dist/templates/fullstack/tests/README.md +40 -1
- package/dist/templates/fullstack/tests/helpers/app-paths.ts +18 -0
- package/dist/templates/fullstack/tests/helpers/paths.ts +33 -0
- package/dist/templates/fullstack/tests/package.json +2 -2
- package/dist/templates/fullstack/tests/playwright.config.ts +7 -3
- package/dist/templates/fullstack/tests/playwright.extensions.ts +88 -1
- package/dist/templates/fullstack/tests/ui/smoke.ui.spec.ts +5 -4
- package/dist/templates/modules/admin-dashboard/files/apps/api/src/account-sessions/account-sessions.routes.spec.ts +152 -0
- package/dist/templates/modules/admin-dashboard/files/apps/api/src/account-sessions/account-sessions.routes.ts +112 -0
- package/dist/templates/modules/admin-dashboard/files/apps/api/src/admin-sessions/admin-sessions.revoker.ts +24 -0
- package/dist/templates/modules/admin-dashboard/files/apps/api/src/admin-sessions/admin-sessions.service.spec.ts +18 -0
- package/dist/templates/modules/admin-dashboard/files/apps/api/src/admin-sessions/admin-sessions.service.ts +36 -13
- package/dist/templates/modules/admin-dashboard/files/apps/api/src/admin.module.ts +13 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.test.ts +37 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.ts +15 -6
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/account-sessions.test.ts +33 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/account-sessions.ts +34 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-flag-settings.test.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-flag-settings.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-flags.ts +12 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-nav.ts +11 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/nav.test.ts +39 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/nav.ts +35 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/registry.svelte.ts +15 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/account-page.svelte +73 -39
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/admin-sidebar.svelte +2 -23
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/data-table.svelte +7 -2
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/data-table.test.ts +30 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/impersonation-banner.svelte +3 -2
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/settings/app-flags-settings.svelte +65 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.svelte +32 -23
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.test.ts +27 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/site-footer.svelte +4 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/site-runtime.svelte +3 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/table-toolbar.svelte +3 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/catalogs/admin-dashboard/en.json +6 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/catalogs/admin-dashboard/ko.json +6 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/app-hooks.ts +11 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/non-indexable-paths.ts +8 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/search-indexing.test.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/search-indexing.ts +5 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/settings/+page.svelte +1 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.server.ts +2 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.svelte +1 -5
- package/dist/templates/modules/admin-dashboard/files/dot-claude/skills/podokit-data-table/SKILL.md +2 -0
- package/dist/templates/modules/admin-dashboard/files/tests/api/account-sessions.api.spec.ts +55 -0
- package/dist/templates/modules/admin-dashboard/files/tests/api/audit.api.spec.ts +1 -1
- package/dist/templates/modules/admin-dashboard/files/tests/api/auth-config.api.spec.ts +159 -170
- package/dist/templates/modules/admin-dashboard/files/tests/api/auth.api.spec.ts +72 -81
- package/dist/templates/modules/admin-dashboard/files/tests/api/email.api.spec.ts +1 -6
- package/dist/templates/modules/admin-dashboard/files/tests/api/profile-image.api.spec.ts +1 -1
- package/dist/templates/modules/admin-dashboard/files/tests/api/site-settings.api.spec.ts +43 -53
- package/dist/templates/modules/admin-dashboard/files/tests/api/users-admin.api.spec.ts +29 -1
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/accounts.ts +24 -6
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/app-accounts.ts +24 -0
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/devices.ts +55 -0
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/disposable-users.ts +5 -3
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/mailpit.ts +3 -9
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/sms.ts +2 -4
- package/dist/templates/modules/admin-dashboard/files/tests/playwright.config.ts +11 -5
- package/dist/templates/modules/admin-dashboard/files/tests/seed.setup.ts +3 -10
- package/dist/templates/modules/admin-dashboard/files/tests/ui/account-flows.ui.spec.ts +4 -5
- package/dist/templates/modules/admin-dashboard/files/tests/ui/account-sessions.ui.spec.ts +46 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/account.ui.spec.ts +62 -59
- package/dist/templates/modules/admin-dashboard/files/tests/ui/app-flags.ui.spec.ts +63 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/appearance.ui.spec.ts +12 -16
- package/dist/templates/modules/admin-dashboard/files/tests/ui/audit.ui.spec.ts +3 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/auth.ui.spec.ts +32 -35
- package/dist/templates/modules/admin-dashboard/files/tests/ui/dashboard.ui.spec.ts +4 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/email-admin.ui.spec.ts +1 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/email.ui.spec.ts +1 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/general-effects.ui.spec.ts +82 -91
- package/dist/templates/modules/admin-dashboard/files/tests/ui/guards.ui.spec.ts +6 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/i18n.ui.spec.ts +16 -20
- package/dist/templates/modules/admin-dashboard/files/tests/ui/impersonation.ui.spec.ts +6 -3
- package/dist/templates/modules/admin-dashboard/files/tests/ui/login-methods.ui.spec.ts +2 -3
- package/dist/templates/modules/admin-dashboard/files/tests/ui/oidc.ui.spec.ts +2 -4
- package/dist/templates/modules/admin-dashboard/files/tests/ui/organizations.ui.spec.ts +5 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/passkey.ui.spec.ts +7 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/same-origin-requests.ui.spec.ts +89 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/sessions.ui.spec.ts +5 -4
- package/dist/templates/modules/admin-dashboard/files/tests/ui/settings-dialogs.ui.spec.ts +67 -73
- package/dist/templates/modules/admin-dashboard/files/tests/ui/settings.ui.spec.ts +84 -93
- package/dist/templates/modules/admin-dashboard/files/tests/ui/table-toolbar.ui.spec.ts +33 -7
- package/dist/templates/modules/admin-dashboard/files/tests/ui/theme-mode.ui.spec.ts +29 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/two-factor.ui.spec.ts +51 -54
- package/dist/templates/modules/admin-dashboard/files/tests/ui/users.ui.spec.ts +10 -9
- package/dist/templates/modules/admin-dashboard/module.manifest.json +7 -2
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit-hook.ts +2 -1
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +5 -1
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.spec.ts +33 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.ts +20 -1
- package/dist/templates/modules/audit-log/module.manifest.json +15 -3
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-app-name.spec.ts +21 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-config-store.ts +13 -1
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-environment.ts +9 -2
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-provider.ts +19 -3
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.module.ts +6 -1
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.runtime.spec.ts +10 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.service.spec.ts +54 -6
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.service.ts +26 -4
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +15 -8
- package/dist/templates/modules/auth/files/apps/api/src/auth/revoke-other-sessions.spec.ts +56 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/revoke-other-sessions.ts +45 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/schema-recheck.spec.ts +86 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/schema-recheck.ts +44 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth-config/auth-config.service.ts +2 -1
- package/dist/templates/modules/auth/files/apps/api/src/migrate.ts +3 -1
- package/dist/templates/modules/auth/files/apps/api/src/settings/app-flags.ts +9 -0
- package/dist/templates/modules/auth/files/apps/api/src/settings/flag-defaults.spec.ts +43 -0
- package/dist/templates/modules/auth/files/apps/api/src/settings/flag-defaults.ts +30 -5
- package/dist/templates/modules/auth/module.manifest.json +8 -2
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/bullmq-job.queue.spec.ts +57 -1
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/bullmq-job.queue.ts +93 -9
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/worker.module.spec.ts +40 -0
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/worker.module.ts +52 -5
- package/dist/templates/modules/bullmq/files/apps/api/src/main-worker.ts +9 -7
- package/dist/templates/modules/bullmq/files/apps/api/src/worker.extensions.ts +13 -0
- package/dist/templates/modules/bullmq/module.manifest.json +5 -1
- package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.worker.spec.ts +2 -0
- package/dist/templates/modules/jobs-local/files/apps/api/src/jobs-local/local-job.queue.spec.ts +87 -1
- package/dist/templates/modules/jobs-local/files/apps/api/src/jobs-local/local-job.queue.ts +93 -3
- package/dist/templates/modules/jobs-local/module.manifest.json +3 -0
- package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.spec.ts +16 -0
- package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +15 -10
- package/dist/templates/modules/mailer/module.manifest.json +1 -1
- package/dist/templates/modules/object-storage-local/files/tests/api/storage-local.api.spec.ts +1 -1
- package/dist/templates/modules/object-storage-s3/files/infra/docker/minio.compose.yml +5 -4
- package/dist/templates/modules/object-storage-s3/files/tests/api/storage.api.spec.ts +1 -1
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.config.spec.ts +2 -59
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.config.ts +0 -65
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.identity.spec.ts +82 -21
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.identity.ts +54 -15
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.spec.ts +43 -5
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.module.ts +10 -2
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.routes.spec.ts +61 -3
- package/dist/templates/modules/rate-limit/files/apps/api/src/rate-limit/rate-limit.routes.ts +48 -15
- package/dist/templates/modules/rate-limit/files/tests/api/rate-limit.api.spec.ts +63 -27
- package/dist/templates/modules/rate-limit/module.manifest.json +6 -9
- package/dist/templates/modules/sse/files/tests/api/events.api.spec.ts +1 -1
- package/dist/templates/todo/AGENTS.md +46 -6
- package/dist/templates/todo/README.md +6 -4
- package/dist/text-diff.d.ts +12 -0
- package/dist/text-diff.js +111 -0
- package/dist/update.d.ts +61 -3
- package/dist/update.js +152 -27
- package/package.json +2 -2
- package/dist/templates/modules/admin-dashboard/files/tests/api/exclusive.api.spec.ts +0 -75
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/exclusive.ts +0 -80
package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.svelte
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import AccountPage from "#lib/components/account-page.svelte";
|
|
3
|
-
import ImpersonationBanner from "#lib/components/impersonation-banner.svelte";
|
|
4
3
|
import LanguageSwitch from "#lib/components/language-switch.svelte";
|
|
5
4
|
import SiteFooter from "#lib/components/site-footer.svelte";
|
|
6
5
|
import ThemeToggle from "#lib/components/theme-toggle.svelte";
|
|
@@ -13,15 +12,12 @@
|
|
|
13
12
|
let {
|
|
14
13
|
data,
|
|
15
14
|
}: {
|
|
16
|
-
data: { user: SessionUser; currentSessionId: string | null; capabilities: Capabilities
|
|
15
|
+
data: { user: SessionUser; currentSessionId: string | null; capabilities: Capabilities };
|
|
17
16
|
} = $props();
|
|
18
17
|
const i18n = getI18n();
|
|
19
18
|
</script>
|
|
20
19
|
|
|
21
20
|
<div class="flex min-h-svh flex-col">
|
|
22
|
-
{#if data.impersonating}
|
|
23
|
-
<ImpersonationBanner email={data.user.email} />
|
|
24
|
-
{/if}
|
|
25
21
|
<header class="flex h-14 items-center gap-2 border-b px-4">
|
|
26
22
|
<Button href="/" variant="ghost">{i18n.t.nav.home}</Button>
|
|
27
23
|
<div class="flex-1"></div>
|
package/dist/templates/modules/admin-dashboard/files/dot-claude/skills/podokit-data-table/SKILL.md
CHANGED
|
@@ -38,6 +38,8 @@ put pagination outside the table.
|
|
|
38
38
|
- Responsive columns: set `hideBelow` to `sm`, `md`, `lg`, or `xl`, then apply
|
|
39
39
|
`cellClass(columnKey)` to the matching `Table.Cell`. Never repeat the
|
|
40
40
|
responsive class by hand; the shared class keeps headers and cells aligned.
|
|
41
|
+
- Header controls such as a select-all checkbox: pass a `head` snippet on the
|
|
42
|
+
column; it replaces the label and sort button. Give the control an aria-label.
|
|
41
43
|
- Give each table an `ariaLabel` and scope Playwright locators to that table.
|
|
42
44
|
- No footer needed: `perPage={0}`.
|
|
43
45
|
- **Search & filters**: put the shared `table-toolbar.svelte` (`TableToolbar`)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { signInOnSeparateDevices } from "../helpers/devices";
|
|
2
|
+
import { expect, test } from "../helpers/disposable-users";
|
|
3
|
+
|
|
4
|
+
const base = process.env.E2E_BASE_URL ?? "http://localhost:5001";
|
|
5
|
+
const origin = { origin: base };
|
|
6
|
+
|
|
7
|
+
type Page = {
|
|
8
|
+
current: { id: string } | null;
|
|
9
|
+
items: Array<{ id: string }>;
|
|
10
|
+
nextCursor: string | null;
|
|
11
|
+
total: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
test("account sessions page the user's own sessions and revoke one by id", async ({ playwright, disposableUsers }) => {
|
|
15
|
+
const email = `api-account-sessions-${Date.now()}@example.com`;
|
|
16
|
+
const password = "Podokit3e-Str0ng!pw";
|
|
17
|
+
await disposableUsers.create({ email, password, name: "Account sessions" });
|
|
18
|
+
expect(await signInOnSeparateDevices(email, password, 4)).toEqual([200, 200, 200, 200]);
|
|
19
|
+
const ctx = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
20
|
+
expect((await ctx.post("/api/auth/sign-in/email", { data: { email, password } })).ok()).toBeTruthy();
|
|
21
|
+
const current = (await (await ctx.get("/api/auth/get-session")).json()) as { session: { id: string } };
|
|
22
|
+
|
|
23
|
+
const first = await ctx.get("/api/account/sessions?limit=2");
|
|
24
|
+
expect(first.ok()).toBeTruthy();
|
|
25
|
+
const firstText = await first.text();
|
|
26
|
+
expect(firstText).not.toContain("token");
|
|
27
|
+
const page1 = JSON.parse(firstText) as Page;
|
|
28
|
+
expect(page1.current?.id).toBe(current.session.id);
|
|
29
|
+
expect(page1.total).toBe(5);
|
|
30
|
+
expect(page1.items).toHaveLength(2);
|
|
31
|
+
expect(page1.nextCursor).toBeTruthy();
|
|
32
|
+
const page2 = (await (await ctx.get(`/api/account/sessions?limit=2&cursor=${encodeURIComponent(page1.nextCursor ?? "")}`)).json()) as Page;
|
|
33
|
+
expect(page2.current?.id).toBe(current.session.id);
|
|
34
|
+
expect(page2.nextCursor).toBeNull();
|
|
35
|
+
const ids = [...page1.items, ...page2.items].map((item) => item.id);
|
|
36
|
+
expect(new Set(ids).size).toBe(4);
|
|
37
|
+
expect(ids).not.toContain(current.session.id);
|
|
38
|
+
|
|
39
|
+
// Another user's session cannot be revoked through this endpoint.
|
|
40
|
+
const otherEmail = `api-account-sessions-other-${Date.now()}@example.com`;
|
|
41
|
+
await disposableUsers.create({ email: otherEmail, password, name: "Other user" });
|
|
42
|
+
const otherUser = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
43
|
+
expect((await otherUser.post("/api/auth/sign-in/email", { data: { email: otherEmail, password } })).ok()).toBeTruthy();
|
|
44
|
+
const otherSession = (await (await otherUser.get("/api/auth/get-session")).json()) as { session: { id: string } };
|
|
45
|
+
const foreign = await ctx.delete(`/api/account/sessions/${encodeURIComponent(otherSession.session.id)}`);
|
|
46
|
+
expect(foreign.status()).toBe(404);
|
|
47
|
+
expect(await foreign.json()).toMatchObject({ error: { code: "ACCOUNT_SESSION_NOT_FOUND" } });
|
|
48
|
+
expect((await otherUser.get("/api/auth/get-session")).ok()).toBeTruthy();
|
|
49
|
+
await otherUser.dispose();
|
|
50
|
+
|
|
51
|
+
const revoked = await ctx.delete(`/api/account/sessions/${encodeURIComponent(ids[0] ?? "")}`);
|
|
52
|
+
expect(revoked.status()).toBe(204);
|
|
53
|
+
expect(((await (await ctx.get("/api/account/sessions?limit=2")).json()) as Page).total).toBe(4);
|
|
54
|
+
await ctx.dispose();
|
|
55
|
+
});
|
|
@@ -128,7 +128,7 @@ test("the audit log rejects bad paging parameters", async ({ playwright }) => {
|
|
|
128
128
|
|
|
129
129
|
// Audit logging is a DB-backed on/off toggle (auth_config `server`, applied live).
|
|
130
130
|
// Runs after the recording tests and restores the flag so nothing else is affected.
|
|
131
|
-
test("audit logging honours the DB on/off toggle @smoke", async ({ playwright, disposableUsers }) => {
|
|
131
|
+
test("audit logging honours the DB on/off toggle @smoke", { tag: "@exclusive" }, async ({ playwright, disposableUsers }) => {
|
|
132
132
|
const admin = await signedIn(playwright, ADMIN);
|
|
133
133
|
test.skip((await admin.get("/api/audit-logs")).status() === 404, "audit-log module not installed");
|
|
134
134
|
const auditLog = async () => (await (await admin.get("/api/account/capabilities")).json()).auditLog as boolean;
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
isUserCreationAllowed,
|
|
5
5
|
} from "../../apps/api/src/auth/feature-gate";
|
|
6
6
|
import { ADMIN } from "../helpers/accounts";
|
|
7
|
-
import { exclusive } from "../helpers/exclusive";
|
|
8
7
|
|
|
9
8
|
const base = process.env.E2E_BASE_URL ?? "http://localhost:5001";
|
|
10
9
|
const origin = { origin: base };
|
|
@@ -17,69 +16,65 @@ async function adminCtx(playwright: import("@playwright/test").PlaywrightWorkerA
|
|
|
17
16
|
return ctx;
|
|
18
17
|
}
|
|
19
18
|
|
|
20
|
-
test("admin can enable Google OAuth from the DB and it applies without a restart", async ({ playwright }) => {
|
|
19
|
+
test("admin can enable Google OAuth from the DB and it applies without a restart", { tag: "@exclusive" }, async ({ playwright }) => {
|
|
21
20
|
test.slow();
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
data: { social: { google: { enabled: true, clientId: "dummy-google-client-id", clientSecret: "dummy-google-client-secret" } } },
|
|
34
|
-
});
|
|
35
|
-
expect(put.ok()).toBeTruthy();
|
|
36
|
-
const view = await put.json();
|
|
37
|
-
expect(view.social.google.enabled).toBe(true);
|
|
38
|
-
expect(view.social.google.hasSecret).toBe(true);
|
|
39
|
-
expect(view.social.google.clientId).toBe("dummy-google-client-id");
|
|
40
|
-
expect("clientSecret" in view.social.google).toBe(false); // secret is never returned
|
|
41
|
-
|
|
42
|
-
// Applied live (no restart): social sign-in now redirects to Google.
|
|
43
|
-
await expect
|
|
44
|
-
.poll(async () => {
|
|
45
|
-
const r = await social();
|
|
46
|
-
return r.ok() ? (((await r.json())?.url as string) ?? "") : "";
|
|
47
|
-
}, { timeout: 8000 })
|
|
48
|
-
.toContain("accounts.google.com");
|
|
49
|
-
const caps = await (await anon.get("/api/account/capabilities")).json();
|
|
50
|
-
expect(caps.providers).toContain("google");
|
|
51
|
-
|
|
52
|
-
await admin.put("/api/account/auth-config", { data: { social: { google: { enabled: false } } } }); // restore
|
|
53
|
-
await anon.dispose();
|
|
54
|
-
await admin.dispose();
|
|
21
|
+
const admin = await adminCtx(playwright);
|
|
22
|
+
await admin.put("/api/account/auth-config", { data: { social: { google: { enabled: false } } } }); // clean start
|
|
23
|
+
const anon = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
24
|
+
const social = () => anon.post("/api/auth/sign-in/social", { data: { provider: "google", callbackURL: `${base}/admin` } });
|
|
25
|
+
|
|
26
|
+
// Before: provider not configured.
|
|
27
|
+
await expect.poll(async () => (await social()).status(), { timeout: 8000 }).toBe(404);
|
|
28
|
+
|
|
29
|
+
// Paste credentials via the admin API.
|
|
30
|
+
const put = await admin.put("/api/account/auth-config", {
|
|
31
|
+
data: { social: { google: { enabled: true, clientId: "dummy-google-client-id", clientSecret: "dummy-google-client-secret" } } },
|
|
55
32
|
});
|
|
33
|
+
expect(put.ok()).toBeTruthy();
|
|
34
|
+
const view = await put.json();
|
|
35
|
+
expect(view.social.google.enabled).toBe(true);
|
|
36
|
+
expect(view.social.google.hasSecret).toBe(true);
|
|
37
|
+
expect(view.social.google.clientId).toBe("dummy-google-client-id");
|
|
38
|
+
expect("clientSecret" in view.social.google).toBe(false); // secret is never returned
|
|
39
|
+
|
|
40
|
+
// Applied live (no restart): social sign-in now redirects to Google.
|
|
41
|
+
await expect
|
|
42
|
+
.poll(async () => {
|
|
43
|
+
const r = await social();
|
|
44
|
+
return r.ok() ? (((await r.json())?.url as string) ?? "") : "";
|
|
45
|
+
}, { timeout: 8000 })
|
|
46
|
+
.toContain("accounts.google.com");
|
|
47
|
+
const caps = await (await anon.get("/api/account/capabilities")).json();
|
|
48
|
+
expect(caps.providers).toContain("google");
|
|
49
|
+
|
|
50
|
+
await admin.put("/api/account/auth-config", { data: { social: { google: { enabled: false } } } }); // restore
|
|
51
|
+
await anon.dispose();
|
|
52
|
+
await admin.dispose();
|
|
56
53
|
});
|
|
57
54
|
|
|
58
|
-
test("admin can add and remove a social provider dynamically", async ({ playwright }) => {
|
|
55
|
+
test("admin can add and remove a social provider dynamically", { tag: "@exclusive" }, async ({ playwright }) => {
|
|
59
56
|
test.slow();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
expect(catalog.map((c) => c.id)).toEqual(expect.arrayContaining(["google", "github", "apple"]));
|
|
65
|
-
|
|
66
|
-
const anon = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
67
|
-
const github = () => anon.post("/api/auth/sign-in/social", { data: { provider: "github", callbackURL: `${base}/admin` } });
|
|
68
|
-
|
|
69
|
-
// Add GitHub (a provider with no env fallback) → applies live, no restart.
|
|
70
|
-
await admin.put("/api/account/auth-config", { data: { social: { github: { enabled: true, clientId: "dummy-github-client-id", clientSecret: "dummy-github-client-secret" } } } });
|
|
71
|
-
await expect
|
|
72
|
-
.poll(async () => { const r = await github(); return r.ok() ? (((await r.json())?.url as string) ?? "") : ""; }, { timeout: 8000 })
|
|
73
|
-
.toContain("github.com");
|
|
74
|
-
|
|
75
|
-
// Remove it → the row is deleted and the provider stops working (again live).
|
|
76
|
-
await admin.put("/api/account/auth-config", { data: { social: { github: { delete: true } } } });
|
|
77
|
-
expect("github" in (await (await admin.get("/api/account/auth-config")).json()).social).toBe(false);
|
|
78
|
-
await expect.poll(async () => (await github()).status(), { timeout: 8000 }).toBe(404);
|
|
57
|
+
const admin = await adminCtx(playwright);
|
|
58
|
+
// The catalog offers providers beyond the two legacy env-backed ones.
|
|
59
|
+
const catalog = (await (await admin.get("/api/account/auth-config")).json()).catalog as Array<{ id: string }>;
|
|
60
|
+
expect(catalog.map((c) => c.id)).toEqual(expect.arrayContaining(["google", "github", "apple"]));
|
|
79
61
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
62
|
+
const anon = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
63
|
+
const github = () => anon.post("/api/auth/sign-in/social", { data: { provider: "github", callbackURL: `${base}/admin` } });
|
|
64
|
+
|
|
65
|
+
// Add GitHub (a provider with no env fallback) → applies live, no restart.
|
|
66
|
+
await admin.put("/api/account/auth-config", { data: { social: { github: { enabled: true, clientId: "dummy-github-client-id", clientSecret: "dummy-github-client-secret" } } } });
|
|
67
|
+
await expect
|
|
68
|
+
.poll(async () => { const r = await github(); return r.ok() ? (((await r.json())?.url as string) ?? "") : ""; }, { timeout: 8000 })
|
|
69
|
+
.toContain("github.com");
|
|
70
|
+
|
|
71
|
+
// Remove it → the row is deleted and the provider stops working (again live).
|
|
72
|
+
await admin.put("/api/account/auth-config", { data: { social: { github: { delete: true } } } });
|
|
73
|
+
expect("github" in (await (await admin.get("/api/account/auth-config")).json()).social).toBe(false);
|
|
74
|
+
await expect.poll(async () => (await github()).status(), { timeout: 8000 }).toBe(404);
|
|
75
|
+
|
|
76
|
+
await anon.dispose();
|
|
77
|
+
await admin.dispose();
|
|
83
78
|
});
|
|
84
79
|
|
|
85
80
|
test("auth-config is admin-only and never leaks secrets @smoke", async ({ playwright }) => {
|
|
@@ -91,50 +86,47 @@ test("auth-config is admin-only and never leaks secrets @smoke", async ({ playwr
|
|
|
91
86
|
await user.dispose();
|
|
92
87
|
});
|
|
93
88
|
|
|
94
|
-
test("automatic logout validates and applies a sliding session lifetime", async ({ playwright }) => {
|
|
95
|
-
|
|
96
|
-
await
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
await admin.dispose();
|
|
133
|
-
}
|
|
134
|
-
});
|
|
89
|
+
test("automatic logout validates and applies a sliding session lifetime", { tag: "@exclusive" }, async ({ playwright }) => {
|
|
90
|
+
const admin = await adminCtx(playwright);
|
|
91
|
+
const freshAdmin = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
expect(
|
|
95
|
+
(await admin.put("/api/account/auth-config", {
|
|
96
|
+
data: { server: { sessionIdleTimeoutMinutes: 4 } },
|
|
97
|
+
})).status(),
|
|
98
|
+
).toBe(400);
|
|
99
|
+
|
|
100
|
+
const enabled = await admin.put("/api/account/auth-config", {
|
|
101
|
+
data: { server: { sessionIdleTimeoutMinutes: 30 } },
|
|
102
|
+
});
|
|
103
|
+
expect(enabled.ok()).toBeTruthy();
|
|
104
|
+
expect((await enabled.json()).server.sessionIdleTimeoutMinutes).toBe(30);
|
|
105
|
+
|
|
106
|
+
const caps = await (await admin.get("/api/account/capabilities")).json();
|
|
107
|
+
expect(caps.sessionIdleTimeoutMinutes).toBe(30);
|
|
108
|
+
|
|
109
|
+
const signIn = await freshAdmin.post("/api/auth/sign-in/email", {
|
|
110
|
+
data: { email: ADMIN.email, password: ADMIN.password },
|
|
111
|
+
});
|
|
112
|
+
expect(signIn.ok()).toBeTruthy();
|
|
113
|
+
expect(signIn.headers()["set-cookie"]).toMatch(/Max-Age=1800(?:;|,)/i);
|
|
114
|
+
|
|
115
|
+
const sessions = (await (await admin.get("/api/auth/list-sessions")).json()) as Array<{
|
|
116
|
+
expiresAt: string;
|
|
117
|
+
}>;
|
|
118
|
+
const latestExpiry = Math.max(...sessions.map((session) => new Date(session.expiresAt).getTime()));
|
|
119
|
+
expect(latestExpiry).toBeLessThanOrEqual(Date.now() + 30 * 60_000 + 10_000);
|
|
120
|
+
} finally {
|
|
121
|
+
await admin.put("/api/account/auth-config", {
|
|
122
|
+
data: { server: { sessionIdleTimeoutMinutes: null } },
|
|
123
|
+
});
|
|
124
|
+
await freshAdmin.dispose();
|
|
125
|
+
await admin.dispose();
|
|
126
|
+
}
|
|
135
127
|
});
|
|
136
128
|
|
|
137
|
-
test("new registrations require approval when the policy is enabled", async ({ playwright }) => {
|
|
129
|
+
test("new registrations require approval when the policy is enabled", { tag: "@exclusive" }, async ({ playwright }) => {
|
|
138
130
|
const admin = await adminCtx(playwright);
|
|
139
131
|
const anon = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
140
132
|
const password = "Podokit3e-Str0ng!pw";
|
|
@@ -213,79 +205,76 @@ test("new registrations require approval when the policy is enabled", async ({ p
|
|
|
213
205
|
}
|
|
214
206
|
});
|
|
215
207
|
|
|
216
|
-
test("closed public sign-up blocks new OAuth users but preserves existing sign-in", async ({ playwright }) => {
|
|
217
|
-
|
|
218
|
-
await
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
clientId: "dummy-google-client-id",
|
|
237
|
-
clientSecret: "dummy-google-client-secret",
|
|
238
|
-
},
|
|
208
|
+
test("closed public sign-up blocks new OAuth users but preserves existing sign-in", { tag: "@exclusive" }, async ({ playwright }) => {
|
|
209
|
+
const admin = await adminCtx(playwright);
|
|
210
|
+
const anon = await playwright.request.newContext({ baseURL: base, extraHTTPHeaders: origin });
|
|
211
|
+
const password = "Podokit3e-Str0ng!pw";
|
|
212
|
+
const adminCreatedEmail = `closed-admin-${Date.now()}@example.com`;
|
|
213
|
+
const initialSite = (await (await anon.get("/api/site/settings")).json()) as {
|
|
214
|
+
allowSignup?: string | null;
|
|
215
|
+
};
|
|
216
|
+
const initialAllowSignup = initialSite.allowSignup === "false" ? "false" : "true";
|
|
217
|
+
let adminCreatedId = "";
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
expect(
|
|
221
|
+
(await admin.put("/api/account/auth-config", {
|
|
222
|
+
data: {
|
|
223
|
+
social: {
|
|
224
|
+
google: {
|
|
225
|
+
enabled: true,
|
|
226
|
+
clientId: "dummy-google-client-id",
|
|
227
|
+
clientSecret: "dummy-google-client-secret",
|
|
239
228
|
},
|
|
240
229
|
},
|
|
241
|
-
}
|
|
242
|
-
).
|
|
243
|
-
|
|
230
|
+
},
|
|
231
|
+
})).ok(),
|
|
232
|
+
).toBeTruthy();
|
|
233
|
+
expect((await admin.put("/api/site/settings", { data: { allowSignup: "false" } })).ok()).toBeTruthy();
|
|
244
234
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
235
|
+
// The site policy uses a short cache shared by sign-up requests and user
|
|
236
|
+
// creation hooks, so wait for the setting to become live.
|
|
237
|
+
await new Promise((resolve) => setTimeout(resolve, 3_200));
|
|
248
238
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
await admin.put("/api/site/settings", { data: { allowSignup: initialAllowSignup } });
|
|
282
|
-
await admin.put("/api/account/auth-config", {
|
|
283
|
-
data: { social: { google: { enabled: false } } },
|
|
284
|
-
});
|
|
285
|
-
await new Promise((resolve) => setTimeout(resolve, 3_200));
|
|
286
|
-
await anon.get("/api/auth/get-session");
|
|
287
|
-
await anon.dispose();
|
|
288
|
-
await admin.dispose();
|
|
239
|
+
const signup = await anon.post("/api/auth/sign-up/email", {
|
|
240
|
+
data: {
|
|
241
|
+
email: `closed-${Date.now()}@example.com`,
|
|
242
|
+
password,
|
|
243
|
+
name: "Closed Registration",
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
expect(signup.status()).toBe(403);
|
|
247
|
+
expect((await signup.json()).code).toBe(PUBLIC_SIGNUP_DISABLED);
|
|
248
|
+
|
|
249
|
+
// OAuth initiation must stay available for existing social users. Only a
|
|
250
|
+
// callback that attempts to create a new user is rejected by the DB hook.
|
|
251
|
+
const social = await anon.post("/api/auth/sign-in/social", {
|
|
252
|
+
data: { provider: "google", callbackURL: `${base}/` },
|
|
253
|
+
});
|
|
254
|
+
expect(social.ok()).toBeTruthy();
|
|
255
|
+
expect(((await social.json()).url as string)).toContain("accounts.google.com");
|
|
256
|
+
expect(isUserCreationAllowed(false, "/callback/google")).toBe(false);
|
|
257
|
+
expect(isUserCreationAllowed(false, undefined)).toBe(false);
|
|
258
|
+
|
|
259
|
+
// Deliberate administrator provisioning remains available while the public
|
|
260
|
+
// site is closed.
|
|
261
|
+
expect(isUserCreationAllowed(false, "/admin/create-user")).toBe(true);
|
|
262
|
+
const adminCreated = await admin.post("/api/auth/admin/create-user", {
|
|
263
|
+
data: { email: adminCreatedEmail, password, name: "Admin Created", role: "user" },
|
|
264
|
+
});
|
|
265
|
+
expect(adminCreated.ok()).toBeTruthy();
|
|
266
|
+
adminCreatedId = ((await adminCreated.json()).user as { id: string }).id;
|
|
267
|
+
} finally {
|
|
268
|
+
if (adminCreatedId) {
|
|
269
|
+
await admin.post("/api/auth/admin/remove-user", { data: { userId: adminCreatedId } });
|
|
289
270
|
}
|
|
290
|
-
|
|
271
|
+
await admin.put("/api/site/settings", { data: { allowSignup: initialAllowSignup } });
|
|
272
|
+
await admin.put("/api/account/auth-config", {
|
|
273
|
+
data: { social: { google: { enabled: false } } },
|
|
274
|
+
});
|
|
275
|
+
await new Promise((resolve) => setTimeout(resolve, 3_200));
|
|
276
|
+
await anon.get("/api/auth/get-session");
|
|
277
|
+
await anon.dispose();
|
|
278
|
+
await admin.dispose();
|
|
279
|
+
}
|
|
291
280
|
});
|