@stacksjs/defaults 0.75.468 → 0.75.475
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/ai/skills/stacks-auth/ACCOUNT-WORKFLOWS.md +17 -0
- package/ai/skills/stacks-mobile/SKILL.md +22 -0
- package/ai/skills/stacks-native/CATALOG.md +19 -19
- package/ai/skills/stacks-storage/UPLOADS-AND-DISKS.md +19 -0
- package/app/Actions/Auth/EnableTwoFactorAction.ts +7 -11
- package/app/Actions/Auth/VerifyTwoFactorLoginAction.ts +4 -4
- package/app/Actions/Dashboard/dashboard-response.ts +20 -0
- package/functions/dashboard-badge.test.ts +42 -0
- package/functions/dashboard-badge.ts +104 -0
- package/functions/dashboard-button.test.ts +33 -0
- package/functions/dashboard-button.ts +44 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +4 -4
- package/resources/components/Dashboard/Analytics/AnalyticsHub.stx +10 -1
- package/resources/components/Dashboard/Data/DataRecords.stx +1 -1
- package/resources/components/Dashboard/Email/InboxMessageList.stx +1 -1
- package/resources/components/Dashboard/MobileSidebar.stx +4 -1
- package/resources/components/Dashboard/Models/ModelsOverview.stx +1 -1
- package/resources/components/Dashboard/UI/Badge.stx +21 -44
- package/resources/components/Dashboard/UI/Button.stx +13 -24
- package/resources/components/Dashboard/UI/Card.stx +8 -0
- package/resources/functions/dashboard/sidebar.ts +12 -3
- package/views/dashboard/layouts/default.stx +43 -18
|
@@ -44,6 +44,23 @@ Source: `src/two-factor.ts` and default auth actions. Evidence:
|
|
|
44
44
|
`two-factor-disable-reauth.test.ts`, `two-factor-challenge-atomicity.test.ts` and
|
|
45
45
|
`two-factor-state-atomicity.test.ts`.
|
|
46
46
|
|
|
47
|
+
### Recovery codes and retryable setup
|
|
48
|
+
|
|
49
|
+
`confirmTwoFactorSetup(userId, code)` verifies the pending server-owned setup
|
|
50
|
+
without discarding it on a mistyped code. It commits factor activation and ten
|
|
51
|
+
recovery codes together. The response returns plaintext codes once; only hashes
|
|
52
|
+
bound to that factor version persist in the auth-owned
|
|
53
|
+
`two_factor_recovery_codes` table. Run `buddy migrate --auth` when upgrading.
|
|
54
|
+
|
|
55
|
+
`verifyTwoFactorCredential(userId, code)` accepts a six-digit authenticator code
|
|
56
|
+
or a one-use recovery code and shares the account's second-factor lockout.
|
|
57
|
+
Call it inside `withTwoFactorChallenge` before issuing the completed session.
|
|
58
|
+
`generateTwoFactorRecoveryCodes(userId)` replaces all backup codes; applications
|
|
59
|
+
must require fresh factor proof before calling it from a management endpoint.
|
|
60
|
+
`remainingTwoFactorRecoveryCodes(userId)` returns only the available count.
|
|
61
|
+
Never log codes, include them in URLs, cache their response or persist plaintext
|
|
62
|
+
in browser or native storage.
|
|
63
|
+
|
|
47
64
|
## Cookie tokens and database sessions
|
|
48
65
|
|
|
49
66
|
Bearer/token-cookie auth and `SessionAuth` database sessions use different
|
|
@@ -294,6 +294,17 @@ appears; `buddy release:notes <tag> --testflight` does it later, and
|
|
|
294
294
|
`buddy release:notes <tag> --play` prints the 500-character Google Play text.
|
|
295
295
|
The code is `@stacksjs/actions/release-notes`.
|
|
296
296
|
|
|
297
|
+
Set `ios.testFlightGroups` to the names of existing internal groups (for example,
|
|
298
|
+
`['Internal testers']`) to distribute processed builds to those groups.
|
|
299
|
+
`release:ios --wait` confirms `IN_BETA_TESTING` and the configured memberships
|
|
300
|
+
before retiring older builds; upload or `VALID` processing alone is insufficient.
|
|
301
|
+
Without a wait, older builds stay available. Resume a tagged release with
|
|
302
|
+
`buddy release:testflight <tag> --wait [minutes]`, preserving its existing
|
|
303
|
+
localized notes; `--dry-run` validates the
|
|
304
|
+
existing internal groups without assigning or expiring builds. This creates no
|
|
305
|
+
testers, public links or external beta review submissions. `--keep-builds` retains
|
|
306
|
+
that many older processed builds in addition to the newly available release.
|
|
307
|
+
|
|
297
308
|
## Device search index
|
|
298
309
|
|
|
299
310
|
`spotlight` says what of the application's own content a device may index, so
|
|
@@ -748,3 +759,14 @@ nativeFonts: {
|
|
|
748
759
|
Craft >= 0.0.229 packages the files and licenses into both apps. iOS registers
|
|
749
760
|
`UIAppFonts`; Android loads asset typefaces. The build rejects older builders,
|
|
750
761
|
missing font files and invalid names. Fonts work without a network request.
|
|
762
|
+
|
|
763
|
+
## Native passkeys
|
|
764
|
+
|
|
765
|
+
Enable `ios.capabilities.passkeys` and a `webcredentials:<relying-party-host>`
|
|
766
|
+
associated domain. Craft >= 0.0.451 supplies the system AuthenticationServices
|
|
767
|
+
sheet. Import `passkeys` from `@stacksjs/mobile`, check
|
|
768
|
+
`await passkeys.isAvailable()`, then pass server-issued JSON WebAuthn options to
|
|
769
|
+
`create(options)` or `get(options)`. Send the JSON credential back to the server
|
|
770
|
+
for verification. The native capability never replaces the server challenge,
|
|
771
|
+
origin and user-verification checks. On unsupported hosts retain another sign-in
|
|
772
|
+
method and offer the installation's secure browser settings.
|
|
@@ -11,14 +11,14 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
11
11
|
| Package | Task guidance | Source entry | Retained tests |
|
|
12
12
|
|---|---|---|---|
|
|
13
13
|
| `@stacksjs/action-runner` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/action-runner/src/index.ts) | 1 |
|
|
14
|
-
| `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) |
|
|
14
|
+
| `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 102 |
|
|
15
15
|
| `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 21 |
|
|
16
16
|
| `@stacksjs/alias` | [`stacks-alias`](../stacks-alias/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/alias/src/index.ts) | 3 |
|
|
17
17
|
| `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 7 |
|
|
18
18
|
| `@stacksjs/api` | [`stacks-api`](../stacks-api/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/index.ts) | 12 |
|
|
19
19
|
| `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 12 |
|
|
20
20
|
| `@stacksjs/audio` | [`stacks-audio`](../stacks-audio/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/audio/src/index.ts) | 3 |
|
|
21
|
-
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) |
|
|
21
|
+
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 131 |
|
|
22
22
|
| `@stacksjs/browser` | [`stacks-browser`](../stacks-browser/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser/src/index.ts) | 9 |
|
|
23
23
|
| `@stacksjs/browser-extension` | [`stacks-browser-extension`](../stacks-browser-extension/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser-extension/src/index.ts) | 9 |
|
|
24
24
|
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 181 |
|
|
@@ -31,11 +31,11 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
31
31
|
| `@stacksjs/cloud` | [`stacks-cloud`](../stacks-cloud/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cloud/src/index.ts) | 10 |
|
|
32
32
|
| `@stacksjs/cms` | [`stacks-cms`](../stacks-cms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cms/src/index.ts) | 5 |
|
|
33
33
|
| `@stacksjs/collections` | [`stacks-collections`](../stacks-collections/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/collections/src/index.ts) | 2 |
|
|
34
|
-
| `@stacksjs/commerce` | [`stacks-commerce`](../stacks-commerce/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/index.ts) |
|
|
34
|
+
| `@stacksjs/commerce` | [`stacks-commerce`](../stacks-commerce/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/index.ts) | 15 |
|
|
35
35
|
| `@stacksjs/composables` | [`stacks-composables`](../stacks-composables/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/composables/src/index.ts) | 18 |
|
|
36
36
|
| `@stacksjs/config` | [`stacks-config`](../stacks-config/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/config/src/index.ts) | 16 |
|
|
37
37
|
| `@stacksjs/cron` | [`stacks-cron`](../stacks-cron/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cron/src/index.ts) | 6 |
|
|
38
|
-
| `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) |
|
|
38
|
+
| `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 140 |
|
|
39
39
|
| `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 22 |
|
|
40
40
|
| `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 2 |
|
|
41
41
|
| `@stacksjs/deploy` | [`stacks-deploy`](../stacks-deploy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/deploy/package.json) | 1 |
|
|
@@ -43,7 +43,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
43
43
|
| `@stacksjs/development` | [`stacks-development`](../stacks-development/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/development/package.json) | 1 |
|
|
44
44
|
| `@stacksjs/dns` | [`stacks-dns`](../stacks-dns/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/index.ts) | 4 |
|
|
45
45
|
| `@stacksjs/docs` | [`stacks-docs`](../stacks-docs/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/docs/src/index.ts) | 2 |
|
|
46
|
-
| `@stacksjs/email` | [`stacks-email`](../stacks-email/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/index.ts) |
|
|
46
|
+
| `@stacksjs/email` | [`stacks-email`](../stacks-email/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/index.ts) | 24 |
|
|
47
47
|
| `@stacksjs/enums` | [`stacks-enums`](../stacks-enums/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/enums/src/index.ts) | 3 |
|
|
48
48
|
| `@stacksjs/env` | [`stacks-env`](../stacks-env/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/env/src/index.ts) | 31 |
|
|
49
49
|
| `@stacksjs/error-handling` | [`stacks-error-handling`](../stacks-error-handling/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/error-handling/src/index.ts) | 10 |
|
|
@@ -86,7 +86,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
86
86
|
| `@stacksjs/slug` | [`stacks-slug`](../stacks-slug/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/src/index.ts) | 5 |
|
|
87
87
|
| `@stacksjs/sms` | [`stacks-sms`](../stacks-sms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sms/src/index.ts) | 6 |
|
|
88
88
|
| `@stacksjs/socials` | [`stacks-socials`](../stacks-socials/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/index.ts) | 18 |
|
|
89
|
-
| `@stacksjs/storage` | [`stacks-storage`](../stacks-storage/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts) |
|
|
89
|
+
| `@stacksjs/storage` | [`stacks-storage`](../stacks-storage/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts) | 50 |
|
|
90
90
|
| `@stacksjs/strings` | [`stacks-strings`](../stacks-strings/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/src/index.ts) | 11 |
|
|
91
91
|
| `@stacksjs/testing` | [`stacks-testing`](../stacks-testing/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/index.ts) | 24 |
|
|
92
92
|
| `@stacksjs/tinker` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/tinker/src/index.ts) | 1 |
|
|
@@ -115,11 +115,11 @@ Evidence directory: [1 retained tests](https://github.com/stacksjs/stacks/blob/m
|
|
|
115
115
|
|
|
116
116
|
Guidance: [`stacks-actions`](../stacks-actions/SKILL.md). Source: [storage/framework/core/actions/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts).
|
|
117
117
|
|
|
118
|
-
Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT_STX_LINT_CONFIG`, `IosToolchainError`, `PUBLICATION_CHECK_SCRIPT`, `XCODE_NOTE`, `assertPublicationAllowed`, `blogSlugify`, `craftSupportsWebkit`, `createComponent`, `createDatabase`, `createFactory`, `createFunction`, `createLanguage`, `createMail`, `createMiddleware`, `createMigration`, `createModel`, `createNotification`, `createPage`, `deleteBlogPost`, `describeDanglingRouteActions`, `describeGitHubRelease`, `discoverPackages`, `ensureDiscoveredPackages`, `findDanglingRouteActions`, `formatProject`, `getBlogPost`, `installStack`, `isDryRunActive`, `lintFix`, `lintProject`, `listBlogPosts`, `listStacks`, `loadIosDependencies`, `loadStxLintConfig`, `macosAgentActionFiles`, `macosAgentDevFiles`, `macosAgentDevManifest`, `macosAgentEntry`, `macosAgentRouteFiles`, `makeAction`, `makeCertificate`, `makeCommand`, `makeComponent`, `makeDatabase`, `makeFunction`, `makeJob`, `makeLanguage`, `makeMail`, `makeNotification`, `makePage`, `makePolicy`, `makeQueueTable`, `makeResource`, `makeStack`, `measureDefaultsDrift`, `pantryExecutable`, `pantryInstallArgs`, `parseFields`, `parseGitHubRemote`, `prepareMacosAgent`, `prepareMacosNative`, `publicationChannels`, `publishGitHubRelease`, `resolveStxSource`, `resolveXcodegen`, `runAdd`, `runCommit`, `runMake`, `runStxLint`, `saveBlogPost`, `scaffoldCrud`, `setDryRun`, `summarizeStructureChanges`, `uninstallStack`, `validateReleaseEvidencePlan`, `verifyReleaseEvidence`, `xcodeDeveloperDir`.
|
|
118
|
+
Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT_STX_LINT_CONFIG`, `IosToolchainError`, `PUBLICATION_CHECK_SCRIPT`, `XCODE_NOTE`, `assertPublicationAllowed`, `blogSlugify`, `craftSupportsWebkit`, `createComponent`, `createDatabase`, `createFactory`, `createFunction`, `createLanguage`, `createMail`, `createMiddleware`, `createMigration`, `createModel`, `createNotification`, `createPage`, `deleteBlogPost`, `describeDanglingRouteActions`, `describeGitHubRelease`, `discoverPackages`, `ensureDiscoveredPackages`, `evaluateReviewOsEvidence`, `findDanglingRouteActions`, `formatProject`, `getBlogPost`, `inspectReviewOsEvidence`, `installStack`, `isDryRunActive`, `lintFix`, `lintProject`, `listBlogPosts`, `listStacks`, `loadIosDependencies`, `loadStxLintConfig`, `macosAgentActionFiles`, `macosAgentDevFiles`, `macosAgentDevManifest`, `macosAgentEntry`, `macosAgentRouteFiles`, `makeAction`, `makeCertificate`, `makeCommand`, `makeComponent`, `makeDatabase`, `makeFunction`, `makeJob`, `makeLanguage`, `makeMail`, `makeNotification`, `makePage`, `makePolicy`, `makeQueueTable`, `makeResource`, `makeStack`, `measureDefaultsDrift`, `pantryExecutable`, `pantryInstallArgs`, `parseFields`, `parseGitHubRemote`, `prepareMacosAgent`, `prepareMacosNative`, `publicationChannels`, `publishGitHubRelease`, `resolveStxSource`, `resolveXcodegen`, `runAdd`, `runCommit`, `runMake`, `runStxLint`, `saveBlogPost`, `scaffoldCrud`, `setDryRun`, `summarizeStructureChanges`, `uninstallStack`, `validateReleaseEvidencePlan`, `verifyReleaseEvidence`, `xcodeDeveloperDir`.
|
|
119
119
|
|
|
120
|
-
Local source modules: [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/action.ts), [src/add.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/add.ts), [src/blog-admin.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/blog-admin.ts), [src/build/ios-toolchain.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/ios-toolchain.ts), [src/build/macos-native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/macos-native.ts), [src/commit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/commit.ts), [src/dev/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/dev/index.ts), [src/discover-packages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/discover-packages.ts), [src/generate/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/generate/index.ts), [src/github-release.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/github-release.ts), [src/helpers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/helpers/index.ts), [src/library/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/library/index.ts), [src/lint/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/lint.ts), [src/lint/stx-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/stx-gate.ts), [src/make-command.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-command.ts), [src/make-job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-job.ts), [src/make-policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-policy.ts), [src/make-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-resource.ts), [src/make.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make.ts), [src/publication-preflight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/publication-preflight.ts), [src/release-evidence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/release-evidence.ts), [src/scaffold-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/scaffold-crud.ts), [src/setup/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/setup/index.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stacks.ts), [src/stx-source.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stx-source.ts), [src/upgrade/package-project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/package-project.ts), [src/upgrade/route-actions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/route-actions.ts).
|
|
120
|
+
Local source modules: [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/action.ts), [src/add.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/add.ts), [src/blog-admin.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/blog-admin.ts), [src/build/ios-toolchain.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/ios-toolchain.ts), [src/build/macos-native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/macos-native.ts), [src/commit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/commit.ts), [src/dev/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/dev/index.ts), [src/discover-packages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/discover-packages.ts), [src/generate/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/generate/index.ts), [src/github-release.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/github-release.ts), [src/helpers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/helpers/index.ts), [src/library/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/library/index.ts), [src/lint/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/lint.ts), [src/lint/stx-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/stx-gate.ts), [src/make-command.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-command.ts), [src/make-job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-job.ts), [src/make-policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-policy.ts), [src/make-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-resource.ts), [src/make.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make.ts), [src/publication-preflight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/publication-preflight.ts), [src/release-evidence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/release-evidence.ts), [src/reviewos-evidence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/reviewos-evidence.ts), [src/scaffold-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/scaffold-crud.ts), [src/setup/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/setup/index.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stacks.ts), [src/stx-source.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stx-source.ts), [src/upgrade/package-project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/package-project.ts), [src/upgrade/route-actions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/route-actions.ts).
|
|
121
121
|
|
|
122
|
-
Evidence directory: [
|
|
122
|
+
Evidence directory: [102 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
123
123
|
|
|
124
124
|
### @stacksjs/ai
|
|
125
125
|
|
|
@@ -187,9 +187,9 @@ Guidance: [`stacks-auth`](../stacks-auth/SKILL.md). Source: [storage/framework/c
|
|
|
187
187
|
|
|
188
188
|
Declared runtime exports: `DEFAULT_ROLE_PACKS`, `adminEmails`, `createBqbRbacStore`, `databaseAdminAccounts`, `generateTOTP`, `generateTOTPSecret`, `nameFromEmail`, `provisionAdmins`, `requestImpersonation`, `seedDefaultRoles`, `totpKeyUri`, `verifyTOTP`.
|
|
189
189
|
|
|
190
|
-
Local source modules: [src/admins.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/admins.ts), [src/authentication.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authentication.ts), [src/authenticator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authenticator.ts), [src/authorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authorizable.ts), [src/browser-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session-store.ts), [src/browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/client.ts), [src/cookie-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/cookie-auth.ts), [src/credential-user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/credential-user.ts), [src/email-verification.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/email-verification.ts), [src/gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/gate.ts), [src/impersonation-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-auth.ts), [src/impersonation-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-store.ts), [src/impersonation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation.ts), [src/magic-link.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/magic-link.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/middleware.ts), [src/oauth-authorization-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-codes.ts), [src/oauth-authorization-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-endpoint.ts), [src/oauth-authorization-requests.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-requests.ts), [src/oauth-authorization-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-response.ts), [src/oauth-authorization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization.ts), [src/oauth-browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-browser-session.ts), [src/oauth-client-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-client-registration.ts), [src/oauth-consent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-consent.ts), [src/oauth-delegated-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-delegated-access.ts), [src/oauth-dynamic-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-dynamic-registration.ts), [src/oauth-grants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-grants.ts), [src/oauth-introspection.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-introspection.ts), [src/oauth-metadata.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-metadata.ts), [src/oauth-pkce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pkce.ts), [src/oauth-protected-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-protected-resource.ts), [src/oauth-provider.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-provider.ts), [src/oauth-pruning.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pruning.ts), [src/oauth-revocation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-revocation.ts), [src/oauth-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-server.ts), [src/oauth-token-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-endpoint.ts), [src/oauth-token-exchange.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-exchange.ts), [src/oauth-token-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-request.ts), [src/oauth-token-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-response.ts), [src/oauth-userinfo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-userinfo.ts), [src/page-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/page-gate.ts), [src/passkey.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkey.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkeys.ts), [src/password/reset-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset-token.ts), [src/password/reset.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset.ts), [src/permissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/permissions.ts), [src/policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/policy.ts), [src/rate-limiter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rate-limiter.ts), [src/rbac-seed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-seed.ts), [src/rbac-store-bqb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-store-bqb.ts), [src/rbac.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac.ts), [src/referrals.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/referrals.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/register.ts), [src/request-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/request-token.ts), [src/session-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-auth.ts), [src/session-handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-handoff.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/socials.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/team.ts), [src/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/tokens.ts), [src/two-factor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor.ts), [src/user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/user.ts).
|
|
190
|
+
Local source modules: [src/admins.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/admins.ts), [src/authentication.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authentication.ts), [src/authenticator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authenticator.ts), [src/authorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authorizable.ts), [src/browser-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session-store.ts), [src/browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/client.ts), [src/cookie-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/cookie-auth.ts), [src/credential-user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/credential-user.ts), [src/email-verification.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/email-verification.ts), [src/gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/gate.ts), [src/impersonation-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-auth.ts), [src/impersonation-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-store.ts), [src/impersonation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation.ts), [src/magic-link.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/magic-link.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/middleware.ts), [src/oauth-authorization-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-codes.ts), [src/oauth-authorization-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-endpoint.ts), [src/oauth-authorization-requests.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-requests.ts), [src/oauth-authorization-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-response.ts), [src/oauth-authorization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization.ts), [src/oauth-browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-browser-session.ts), [src/oauth-client-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-client-registration.ts), [src/oauth-consent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-consent.ts), [src/oauth-delegated-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-delegated-access.ts), [src/oauth-dynamic-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-dynamic-registration.ts), [src/oauth-grants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-grants.ts), [src/oauth-introspection.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-introspection.ts), [src/oauth-metadata.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-metadata.ts), [src/oauth-pkce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pkce.ts), [src/oauth-protected-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-protected-resource.ts), [src/oauth-provider.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-provider.ts), [src/oauth-pruning.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pruning.ts), [src/oauth-revocation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-revocation.ts), [src/oauth-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-server.ts), [src/oauth-token-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-endpoint.ts), [src/oauth-token-exchange.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-exchange.ts), [src/oauth-token-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-request.ts), [src/oauth-token-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-response.ts), [src/oauth-userinfo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-userinfo.ts), [src/page-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/page-gate.ts), [src/passkey.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkey.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkeys.ts), [src/password/reset-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset-token.ts), [src/password/reset.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset.ts), [src/permissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/permissions.ts), [src/policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/policy.ts), [src/rate-limiter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rate-limiter.ts), [src/rbac-seed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-seed.ts), [src/rbac-store-bqb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-store-bqb.ts), [src/rbac.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac.ts), [src/referrals.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/referrals.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/register.ts), [src/request-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/request-token.ts), [src/session-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-auth.ts), [src/session-handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-handoff.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/socials.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/team.ts), [src/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/tokens.ts), [src/two-factor-recovery-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor-recovery-codes.ts), [src/two-factor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor.ts), [src/user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/user.ts).
|
|
191
191
|
|
|
192
|
-
Evidence directory: [
|
|
192
|
+
Evidence directory: [131 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
193
193
|
|
|
194
194
|
### @stacksjs/browser
|
|
195
195
|
|
|
@@ -317,7 +317,7 @@ Declared runtime exports: `PriceFormatError`, `auctions`, `breakdownFor`, `carts
|
|
|
317
317
|
|
|
318
318
|
Local source modules: [src/auctions/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/auctions/index.ts), [src/carts/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/carts/index.ts), [src/catalog.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/catalog.ts), [src/coupons/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/coupons/index.ts), [src/customers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/customers/index.ts), [src/devices/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/devices/index.ts), [src/errors/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/errors/index.ts), [src/gift-cards/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/gift-cards/index.ts), [src/imports/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/imports/index.ts), [src/inventory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/inventory.ts), [src/money.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/money.ts), [src/orders/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/orders/index.ts), [src/payments/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/payments/index.ts), [src/products/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/products/index.ts), [src/receipt-text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/receipt-text.ts), [src/receipts/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/receipts/index.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/register.ts), [src/releases.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/releases.ts), [src/sales-tax.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/sales-tax.ts), [src/shippings/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/shippings/index.ts), [src/tax-input.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/tax-input.ts), [src/tax/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/tax/index.ts), [src/waitlists/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/waitlists/index.ts), [src/waitlists/restaurant/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/waitlists/restaurant/index.ts).
|
|
319
319
|
|
|
320
|
-
Evidence directory: [
|
|
320
|
+
Evidence directory: [15 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
321
321
|
|
|
322
322
|
### @stacksjs/composables
|
|
323
323
|
|
|
@@ -357,7 +357,7 @@ Declared runtime exports: `Database`, `EntityQueryBuilder`, `__flushAfterCommitN
|
|
|
357
357
|
|
|
358
358
|
Local source modules: [src/affected-rows.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/affected-rows.ts), [src/auth-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/auth-tables.ts), [src/custom/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/custom/index.ts), [src/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/database.ts), [src/datetime-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/datetime-columns.ts), [src/ddl-constraints.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ddl-constraints.ts), [src/defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/defaults.ts), [src/dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/dialect.ts), [src/driver-config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/driver-config.ts), [src/drivers/dynamodb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/dynamodb.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/index.ts), [src/ensure-database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ensure-database.ts), [src/erd.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/erd.ts), [src/fk-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/fk-audit.ts), [src/framework-renames.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-renames.ts), [src/framework-route-admission.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-route-admission.ts), [src/hand-written-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/hand-written-migrations.ts), [src/ignored-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ignored-migrations.ts), [src/index-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index-shape.ts), [src/managed-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/managed-columns.ts), [src/migration-dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-dialect.ts), [src/migration-ledger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-ledger.ts), [src/migration-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-names.ts), [src/migration-path.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-path.ts), [src/migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migrations.ts), [src/model-sources.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/model-sources.ts), [src/notification-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/notification-tables.ts), [src/package-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-migrations.ts), [src/package-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-models.ts), [src/query-logger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/query-logger.ts), [src/rbac-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/rbac-tables.ts), [src/relation-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/relation-columns.ts), [src/replicas.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/replicas.ts), [src/row-lease.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/row-lease.ts), [src/row-lock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/row-lock.ts), [src/safe-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/safe-migrations.ts), [src/schema-align.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-align.ts), [src/schema-drift.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-drift.ts), [src/seeder.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/seeder.ts), [src/shadowed-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/shadowed-models.ts), [src/sql-helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/sql-helpers.ts), [src/trait-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/trait-tables.ts), [src/transaction-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/transaction-context.ts), [src/transaction-options.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/transaction-options.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/types.ts), [src/unique-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/unique-audit.ts), [src/utc-defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utc-defaults.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utils.ts), [src/uuid-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/uuid-columns.ts), [src/vschema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/vschema.ts).
|
|
359
359
|
|
|
360
|
-
Evidence directory: [
|
|
360
|
+
Evidence directory: [140 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
361
361
|
|
|
362
362
|
### @stacksjs/datetime
|
|
363
363
|
|
|
@@ -431,7 +431,7 @@ Declared runtime exports: `discoverMailables`, `inlineCss`, `loadSampleProps`, `
|
|
|
431
431
|
|
|
432
432
|
Local source modules: [src/css-inliner.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/css-inliner.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/drivers/index.ts), [src/email.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/email.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/idempotency.ts), [src/inbound-parser.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/inbound-parser.ts), [src/inbox-mailbox.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/inbox-mailbox.ts), [src/mailable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/mailable.ts), [src/mime-preview.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/mime-preview.ts), [src/preview-ui.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/preview-ui.ts), [src/preview.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/preview.ts), [src/sdk/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/sdk/index.ts), [src/suppression.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/suppression.ts), [src/template.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/template.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/types.ts), [src/unsubscribe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/unsubscribe.ts), [src/webhook-dedup.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/webhook-dedup.ts), [src/webhook-events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/webhook-events.ts), [src/webhook-handlers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/webhook-handlers.ts), [src/webhook-signatures.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/webhook-signatures.ts).
|
|
433
433
|
|
|
434
|
-
Evidence directory: [
|
|
434
|
+
Evidence directory: [24 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
435
435
|
|
|
436
436
|
### @stacksjs/enums
|
|
437
437
|
|
|
@@ -591,7 +591,7 @@ Guidance: [`stacks-mobile`](../stacks-mobile/SKILL.md). Source: [storage/framewo
|
|
|
591
591
|
|
|
592
592
|
Declared runtime exports: `appReview`, `biometrics`, `brightness`, `camera`, `createVoiceRecorder`, `deepLinks`, `device`, `getNativeMobileBridge`, `haptics`, `health`, `heartRate`, `isNativeMobile`, `keepAwake`, `lifecycle`, `liveActivities`, `location`, `mobile`, `music`, `network`, `normalizeDeepLinkURL`, `notifications`, `onMobileReady`, `permissions`, `pushNotifications`, `secureStorage`, `share`, `snapshots`, `speech`, `splash`, `voiceRecordingFormData`, `watchConnectivity`, `whenNativeMobile`, `withNativeFeedback`.
|
|
593
593
|
|
|
594
|
-
Local source modules: [src/bridge.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/bridge.ts), [src/controls.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/controls.ts), [src/crash-reporting.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/crash-reporting.ts), [src/crypto.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/crypto.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/events.ts), [src/gestures.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/gestures.ts), [src/indoor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/indoor.ts), [src/native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/native.ts), [src/navigation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/navigation.ts), [src/refresh-control.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/refresh-control.ts), [src/route.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/route.ts), [src/scheduled-workouts.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/scheduled-workouts.ts), [src/session-clock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/session-clock.ts), [src/sheet-gesture.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheet-gesture.ts), [src/sheets.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheets.ts), [src/shell.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/shell.ts), [src/spotlight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/spotlight.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/storage.ts), [src/tab-bar.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/tab-bar.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/types.ts), [src/voice-recorder.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/voice-recorder.ts).
|
|
594
|
+
Local source modules: [src/bridge.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/bridge.ts), [src/controls.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/controls.ts), [src/crash-reporting.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/crash-reporting.ts), [src/crypto.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/crypto.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/events.ts), [src/gestures.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/gestures.ts), [src/indoor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/indoor.ts), [src/native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/native.ts), [src/navigation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/navigation.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/passkeys.ts), [src/refresh-control.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/refresh-control.ts), [src/route.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/route.ts), [src/scheduled-workouts.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/scheduled-workouts.ts), [src/session-clock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/session-clock.ts), [src/sheet-gesture.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheet-gesture.ts), [src/sheets.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheets.ts), [src/shell.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/shell.ts), [src/spotlight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/spotlight.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/storage.ts), [src/tab-bar.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/tab-bar.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/types.ts), [src/voice-recorder.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/voice-recorder.ts).
|
|
595
595
|
|
|
596
596
|
Evidence directory: [23 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
597
597
|
|
|
@@ -637,7 +637,7 @@ Evidence directory: [10 retained tests](https://github.com/stacksjs/stacks/blob/
|
|
|
637
637
|
|
|
638
638
|
Guidance: [`stacks-orm`](../stacks-orm/SKILL.md). Source: [storage/framework/core/orm/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts).
|
|
639
639
|
|
|
640
|
-
Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`, `Author`, `Automation`, `AutomationRun`, `BILLABLE_INSTANCE_METHODS`, `Bid`, `Board`, `BoardColumn`, `Campaign`, `CampaignSend`, `CampaignVariant`, `Card`, `CardAttachment`, `CardComment`, `Cart`, `CartItem`, `Categorizable`, `Category`, `Comment`, `CommunicationSuppression`, `ConsentEvent`, `Coupon`, `Courier`, `CourierPing`, `Customer`, `DeliveryRoute`, `DeliveryStop`, `Deployment`, `DigitalDelivery`, `EmailIdempotency`, `EmailList`, `EmailListSubscriber`, `EmailSuppression`, `EmailWebhookEvent`, `ErrorModel`, `FailedJob`, `FeedbackToken`, `Form`, `FormField`, `FormSubmission`, `GdprRequest`, `GiftCard`, `Job`, `Label`, `LicenseKey`, `Log`, `LoyaltyPoint`, `LoyaltyReward`, `MagicLinkToken`, `MailPreference`, `Manufacturer`, `Menu`, `MenuItem`, `Notification`, `NotificationDelivery`, `Order`, `OrderIdempotency`, `OrderItem`, `Page`, `PageRevision`, `Payment`, `PaymentMethod`, `PaymentProduct`, `PaymentTransaction`, `PaymentWebhookEvent`, `PersonalAccessToken`, `Pledge`, `Post`, `PrintDevice`, `Product`, `ProductUnit`, `ProductVariant`, `QueryLog`, `Receipt`, `Redirect`, `Referral`, `ReferralCode`, `Release`, `Request`, `Review`, `SenderDomain`, `ShippingMethod`, `ShippingRate`, `ShippingZone`, `Site`, `SiteDomain`, `SmsOptOut`, `SocialAccount`, `SocialPost`, `StorageItem`, `StorageItemTask`, `Subscriber`, `SubscriberEmail`, `Subscription`, `SubscriptionNotOwnedError`, `Tag`, `TaxRate`, `Team`, `TeamInvitation`, `TeamMember`, `Transaction`, `UsageEvent`, `User`, `WaitlistProduct`, `WaitlistRestaurant`, `Websocket`, `buildDatabaseSchema`, `collectEncryptedAttributes`, `createAuditMethods`, `createCategorizableMethods`, `createCommentableMethods`, `createLikeableMethods`, `createTaggableMethods`, `customerOwnership`, `decryptValue`, `encryptValue`, `enrichPaginatorUrls`, `filterFillable`, `frameworkModelFeature`, `getWritableFields`, `isBillable`, `isCursorPaginator`, `isEncrypted`, `isPaginator`, `isSimplePaginator`, `isUniqueViolation`, `mapWriteError`, `modelGlobalNames`, `ormReady`, `parentOwnership`, `parseCursor`, `renderDatabaseTypeFile`, `resolveCursorArgs`, `resolvePageArgs`, `selfOwnership`, `setAuditUser`, `siteOwnership`, `teamMembershipOwnership`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`, `toSnakeCaseKeys`.
|
|
640
|
+
Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`, `Author`, `Automation`, `AutomationRun`, `BILLABLE_INSTANCE_METHODS`, `Bid`, `Board`, `BoardColumn`, `Campaign`, `CampaignSend`, `CampaignVariant`, `Card`, `CardAttachment`, `CardComment`, `Cart`, `CartItem`, `Categorizable`, `Category`, `Comment`, `CommunicationSuppression`, `ConsentEvent`, `Coupon`, `Courier`, `CourierPing`, `Customer`, `DeliveryRoute`, `DeliveryStop`, `Deployment`, `DigitalDelivery`, `EmailIdempotency`, `EmailList`, `EmailListSubscriber`, `EmailSuppression`, `EmailWebhookEvent`, `ErrorModel`, `FailedJob`, `FeedbackToken`, `Form`, `FormField`, `FormSubmission`, `GdprRequest`, `GiftCard`, `Job`, `Label`, `LicenseKey`, `Log`, `LoyaltyPoint`, `LoyaltyReward`, `MagicLinkToken`, `MailPreference`, `Manufacturer`, `Menu`, `MenuItem`, `ModelUnavailableError`, `Notification`, `NotificationDelivery`, `Order`, `OrderIdempotency`, `OrderItem`, `Page`, `PageRevision`, `Payment`, `PaymentMethod`, `PaymentProduct`, `PaymentTransaction`, `PaymentWebhookEvent`, `PersonalAccessToken`, `Pledge`, `Post`, `PrintDevice`, `Product`, `ProductUnit`, `ProductVariant`, `QueryLog`, `Receipt`, `Redirect`, `Referral`, `ReferralCode`, `Release`, `Request`, `Review`, `SenderDomain`, `ShippingMethod`, `ShippingRate`, `ShippingZone`, `Site`, `SiteDomain`, `SmsOptOut`, `SocialAccount`, `SocialPost`, `StorageItem`, `StorageItemTask`, `Subscriber`, `SubscriberEmail`, `Subscription`, `SubscriptionNotOwnedError`, `Tag`, `TaxRate`, `Team`, `TeamInvitation`, `TeamMember`, `Transaction`, `UsageEvent`, `User`, `WaitlistProduct`, `WaitlistRestaurant`, `Websocket`, `buildDatabaseSchema`, `collectEncryptedAttributes`, `createAuditMethods`, `createCategorizableMethods`, `createCommentableMethods`, `createLikeableMethods`, `createTaggableMethods`, `customerOwnership`, `decryptValue`, `encryptValue`, `enrichPaginatorUrls`, `filterFillable`, `frameworkModelFeature`, `getWritableFields`, `isBillable`, `isCursorPaginator`, `isEncrypted`, `isPaginator`, `isSimplePaginator`, `isUniqueViolation`, `mapWriteError`, `modelGlobalNames`, `ormReady`, `parentOwnership`, `parseCursor`, `renderDatabaseTypeFile`, `resolveCursorArgs`, `resolvePageArgs`, `selfOwnership`, `setAuditUser`, `siteOwnership`, `teamMembershipOwnership`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`, `toSnakeCaseKeys`.
|
|
641
641
|
|
|
642
642
|
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
643
643
|
|
|
@@ -839,11 +839,11 @@ Evidence directory: [18 retained tests](https://github.com/stacksjs/stacks/blob/
|
|
|
839
839
|
|
|
840
840
|
Guidance: [`stacks-storage`](../stacks-storage/SKILL.md). Source: [storage/framework/core/storage/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts).
|
|
841
841
|
|
|
842
|
-
Declared runtime exports: `PathSanitizeError`, `Storage`, `StorageManager`, `UploadedFile`, `azureDisk`, `backblazeDisk`, `clearRevokedSignedStorageTokens`, `configFromEnv`, `createSignedStorageToken`, `detectMimeFromMagicBytes`, `ensureBucket`, `ensureConfiguredBuckets`, `fileInfo`, `fileInfoFromBytes`, `fileKind`, `filebaseDisk`, `gcsDisk`, `hetznerDisk`, `isPreviewable`, `isSignedStorageTokenRevoked`, `localDisk`, `parseDiskPath`, `r2Disk`, `resolveMime`, `revokeSignedStorageToken`, `s3Disk`, `sanitizePresignedDir`, `sanitizePresignedFilename`, `serveFile`, `signS3PresignedPost`, `storage`, `uploadedFile`, `uploadedFiles`, `verifySignedStorageToken`, `verifyUploadedMime`.
|
|
842
|
+
Declared runtime exports: `DirectoryListingChangedError`, `PathSanitizeError`, `Storage`, `StorageManager`, `UploadedFile`, `azureDisk`, `backblazeDisk`, `clearRevokedSignedStorageTokens`, `configFromEnv`, `createSignedStorageToken`, `detectMimeFromMagicBytes`, `ensureBucket`, `ensureConfiguredBuckets`, `fileInfo`, `fileInfoFromBytes`, `fileKind`, `filebaseDisk`, `gcsDisk`, `hetznerDisk`, `isPreviewable`, `isSignedStorageTokenRevoked`, `localDisk`, `parseDiskPath`, `r2Disk`, `resolveMime`, `revokeSignedStorageToken`, `s3Disk`, `sanitizePresignedDir`, `sanitizePresignedFilename`, `serveFile`, `signS3PresignedPost`, `storage`, `uploadedFile`, `uploadedFiles`, `verifySignedStorageToken`, `verifyUploadedMime`.
|
|
843
843
|
|
|
844
|
-
Local source modules: [src/adapters/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/adapters/index.ts), [src/bounded-text-file.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/bounded-text-file.ts), [src/completed-artifact-directory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/completed-artifact-directory.ts), [src/copy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/copy.ts), [src/delete.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/delete.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/drivers/index.ts), [src/facade.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/facade.ts), [src/file-info.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/file-info.ts), [src/files.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/files.ts), [src/folders.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/folders.ts), [src/fs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/fs.ts), [src/glob.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/glob.ts), [src/hash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/hash.ts), [src/helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/helpers.ts), [src/mime-verify.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/mime-verify.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/path-sanitize.ts), [src/provision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/provision.ts), [src/s3-presigned-post.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/s3-presigned-post.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/signed-url.ts), [src/static-serve.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/static-serve.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/storage.ts), [src/temporary-workspaces.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/temporary-workspaces.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/types.ts), [src/types/filesystem.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/types/filesystem.ts), [src/uploaded-file.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/uploaded-file.ts), [src/zip.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/zip.ts).
|
|
844
|
+
Local source modules: [src/adapters/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/adapters/index.ts), [src/bounded-text-file.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/bounded-text-file.ts), [src/completed-artifact-directory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/completed-artifact-directory.ts), [src/copy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/copy.ts), [src/delete.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/delete.ts), [src/directory-page.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/directory-page.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/drivers/index.ts), [src/facade.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/facade.ts), [src/file-info.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/file-info.ts), [src/files.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/files.ts), [src/folders.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/folders.ts), [src/fs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/fs.ts), [src/glob.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/glob.ts), [src/hash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/hash.ts), [src/helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/helpers.ts), [src/mime-verify.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/mime-verify.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/path-sanitize.ts), [src/provision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/provision.ts), [src/s3-presigned-post.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/s3-presigned-post.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/signed-url.ts), [src/static-serve.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/static-serve.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/storage.ts), [src/temporary-workspaces.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/temporary-workspaces.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/types.ts), [src/types/filesystem.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/types/filesystem.ts), [src/uploaded-file.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/uploaded-file.ts), [src/zip.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/zip.ts).
|
|
845
845
|
|
|
846
|
-
Evidence directory: [
|
|
846
|
+
Evidence directory: [50 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
847
847
|
|
|
848
848
|
### @stacksjs/strings
|
|
849
849
|
|
|
@@ -131,3 +131,22 @@ tenant. Underlying optional methods still need driver support.
|
|
|
131
131
|
|
|
132
132
|
Source: `signed-url.ts`, `static-serve.ts`, `adapters/scoped.ts`; evidence:
|
|
133
133
|
`tests/scoped.test.ts`, `static-serve.test.ts`, `path-sanitize.test.ts`.
|
|
134
|
+
|
|
135
|
+
## Resumable inventories
|
|
136
|
+
|
|
137
|
+
Use a disk's optional `listPage(path, { limit, cursor })` for a durable shallow
|
|
138
|
+
inventory. Each page contains at most 1,000 entries (100 by default) and an
|
|
139
|
+
opaque `nextCursor`. Persist the cursor only in the transaction that enrolls the
|
|
140
|
+
whole page; retrying a page must be idempotent. A null cursor completes the pass.
|
|
141
|
+
Do not emulate this API by materializing `list()` when an adapter lacks it.
|
|
142
|
+
|
|
143
|
+
S3 forwards the provider's continuation token and MaxKeys. Local/Bun disks on
|
|
144
|
+
Darwin or glibc Linux use a bounded 32 KiB native directory block plus its record
|
|
145
|
+
position, preserving that cursor across process restarts without rescanning the
|
|
146
|
+
preceding directory. Local cursors bind to directory identity and modification
|
|
147
|
+
times. `DirectoryListingChangedError` means restart that directory from null;
|
|
148
|
+
previously enrolled records remain valid. Concurrent additions are therefore
|
|
149
|
+
visited during the restarted pass. Symlinks and special files are excluded.
|
|
150
|
+
Permission/provider failures throw and must leave the durable cursor unchanged.
|
|
151
|
+
Windows and unsupported libc hosts fail explicitly rather than claiming a
|
|
152
|
+
bounded inventory through an unbounded fallback.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions/runtime'
|
|
2
|
-
import {
|
|
2
|
+
import { confirmTwoFactorSetup } from '@stacksjs/auth'
|
|
3
3
|
import { response } from '@stacksjs/router'
|
|
4
4
|
import { schema } from '@stacksjs/validation/runtime'
|
|
5
5
|
|
|
@@ -22,16 +22,12 @@ export default new Action({
|
|
|
22
22
|
|
|
23
23
|
const code = request.get('code')
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
const
|
|
28
|
-
if (!
|
|
29
|
-
return response.
|
|
25
|
+
// Confirm the server-owned setup atomically. A mistyped code keeps the QR
|
|
26
|
+
// usable, and recovery codes are returned once after the factor is saved.
|
|
27
|
+
const result = await confirmTwoFactorSetup(user.id as number, code)
|
|
28
|
+
if (!result.enabled)
|
|
29
|
+
return response.json({ error: result.reason === 'missing' ? 'Setup expired. Start setup again.' : result.reason === 'already_enabled' ? 'Two-factor authentication is already enabled.' : 'Invalid code. Check your authenticator app and try again.' }, { status: 422, headers: { 'Cache-Control': 'private, no-store' } })
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
if (!enabled)
|
|
33
|
-
return response.unauthorized('Invalid code — please check your authenticator app and try again.')
|
|
34
|
-
|
|
35
|
-
return response.json({ enabled: true })
|
|
31
|
+
return response.json(result, { headers: { 'Cache-Control': 'private, no-store' } })
|
|
36
32
|
},
|
|
37
33
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions/runtime'
|
|
2
|
-
import { Auth, authCookieForBrowserSession, resolveBrowserSessionPolicy,
|
|
2
|
+
import { Auth, authCookieForBrowserSession, resolveBrowserSessionPolicy, verifyTwoFactorCredential, withTwoFactorChallenge } from '@stacksjs/auth'
|
|
3
3
|
import { response } from '@stacksjs/router'
|
|
4
4
|
import { schema } from '@stacksjs/validation/runtime'
|
|
5
5
|
|
|
@@ -14,8 +14,8 @@ export default new Action({
|
|
|
14
14
|
message: 'A challenge token is required.',
|
|
15
15
|
},
|
|
16
16
|
code: {
|
|
17
|
-
rule: schema.string().min(6).max(
|
|
18
|
-
message: '
|
|
17
|
+
rule: schema.string().min(6).max(64).required(),
|
|
18
|
+
message: 'Enter an authenticator code or a recovery code.',
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
21
|
|
|
@@ -28,7 +28,7 @@ export default new Action({
|
|
|
28
28
|
// LoginAction, not retry — mirrors the WebAuthn challenge
|
|
29
29
|
// delete-on-read semantics in passkey.ts (stacksjs/stacks#1866).
|
|
30
30
|
const result = await withTwoFactorChallenge(challengeToken, async (userId, challenge) => {
|
|
31
|
-
if (!await
|
|
31
|
+
if (!await verifyTwoFactorCredential(userId, code)) return null
|
|
32
32
|
const policy = resolveBrowserSessionPolicy(challenge.remembered)
|
|
33
33
|
return Auth.loginUsingId(userId, {
|
|
34
34
|
expiresInMinutes: policy.expiresInMinutes,
|
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
import type { ResponseStatus } from '@stacksjs/bun-router'
|
|
2
2
|
import { response } from '@stacksjs/router'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The feature whose models this error says were never loaded, if it is the
|
|
6
|
+
* ORM's `ModelUnavailableError` for a feature that is off.
|
|
7
|
+
*/
|
|
8
|
+
function disabledFeature(error: unknown): string | undefined {
|
|
9
|
+
if (!(error instanceof Error) || error.name !== 'ModelUnavailableError')
|
|
10
|
+
return undefined
|
|
11
|
+
const feature = (error as Error & { feature?: unknown }).feature
|
|
12
|
+
return typeof feature === 'string' && feature ? feature : undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
export function dashboardOperationalError(
|
|
5
16
|
error: unknown,
|
|
6
17
|
message: string,
|
|
7
18
|
action: string,
|
|
8
19
|
status: ResponseStatus = 503,
|
|
9
20
|
): Response {
|
|
21
|
+
// A page whose feature is off is not an outage, and saying "could not be
|
|
22
|
+
// read" sent people looking at their database (stacksjs/stacks#3184).
|
|
23
|
+
const feature = disabledFeature(error)
|
|
24
|
+
if (feature) {
|
|
25
|
+
console.warn(`[dashboard/api] ${action}: the '${feature}' feature is off`)
|
|
26
|
+
return response.json({
|
|
27
|
+
message: `${feature.charAt(0).toUpperCase()}${feature.slice(1)} is turned off for this app, so this page has no data. Set \`enabled: true\` in config/${feature}.ts to use it.`,
|
|
28
|
+
}, 404)
|
|
29
|
+
}
|
|
10
30
|
console.error(`[dashboard/api] ${action} failed:`, error)
|
|
11
31
|
return response.json({ message }, status)
|
|
12
32
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { badgeClasses, badgeClassToggles, badgeDotClasses, badgeDotClassToggles, badgeShowsDot } from './dashboard-badge'
|
|
3
|
+
|
|
4
|
+
describe('dashboard badge classes', () => {
|
|
5
|
+
test('a variant picks its colour', () => {
|
|
6
|
+
expect(badgeClasses('info')).toContain('bg-cyan-500/15 text-cyan-600')
|
|
7
|
+
expect(badgeClasses('success')).toContain('bg-green-500/15 text-green-600')
|
|
8
|
+
expect(badgeClasses('danger', 'sm', 'full', true)).toContain('border-red-500/40 text-red-600')
|
|
9
|
+
expect(badgeDotClasses('warning')).toContain('bg-orange-500')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('an unknown or missing value falls back rather than printing undefined', () => {
|
|
13
|
+
expect(badgeClasses('nope', 'huge')).toBe(badgeClasses())
|
|
14
|
+
expect(badgeClasses(undefined)).toContain('bg-black/[0.06] text-neutral-600')
|
|
15
|
+
expect(badgeDotClasses('nope')).toBe(badgeDotClasses())
|
|
16
|
+
expect(badgeClasses()).not.toContain('undefined')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('a flag that arrived as an attribute string reads as the attribute means', () => {
|
|
20
|
+
expect(badgeClasses('info', 'sm', 'full', 'false')).toBe(badgeClasses('info'))
|
|
21
|
+
expect(badgeClasses('info', 'sm', 'full', 'true')).toBe(badgeClasses('info', 'sm', 'full', true))
|
|
22
|
+
expect(badgeShowsDot('true')).toBe(true)
|
|
23
|
+
expect(badgeShowsDot('')).toBe(true)
|
|
24
|
+
expect(badgeShowsDot('false')).toBe(false)
|
|
25
|
+
expect(badgeShowsDot(undefined)).toBe(false)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('the live toggles turn a grey first paint into exactly the bound variant', () => {
|
|
29
|
+
// What the browser does with an object `:class`: add the true keys, remove
|
|
30
|
+
// the false ones, leave every other class alone.
|
|
31
|
+
const apply = (start: string, toggles: Record<string, boolean>) => {
|
|
32
|
+
const list = new Set(start.split(' '))
|
|
33
|
+
for (const [token, on] of Object.entries(toggles)) on ? list.add(token) : list.delete(token)
|
|
34
|
+
return [...list].sort()
|
|
35
|
+
}
|
|
36
|
+
const sorted = (classes: string) => classes.split(' ').sort()
|
|
37
|
+
|
|
38
|
+
expect(apply(badgeClasses('default'), badgeClassToggles('info'))).toEqual(sorted(badgeClasses('info')))
|
|
39
|
+
expect(apply(badgeClasses('success', 'xs'), badgeClassToggles('danger', 'lg', 'default', 'true'))).toEqual(sorted(badgeClasses('danger', 'lg', 'default', true)))
|
|
40
|
+
expect(apply(badgeDotClasses('default'), badgeDotClassToggles('warning'))).toEqual(sorted(badgeDotClasses('warning')))
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The classes a dashboard `<Badge>` renders.
|
|
3
|
+
*
|
|
4
|
+
* A pure function of the props, shared by the badge's server render (the first
|
|
5
|
+
* paint) and its client script (every later value). The client half is why
|
|
6
|
+
* this is a module: most callers bind `:variant` to data that arrives after
|
|
7
|
+
* hydration, the class computed at the server render never changed, and every
|
|
8
|
+
* such badge stayed the default grey (stacksjs/stacks#3179). A server script's
|
|
9
|
+
* function cannot cross to the client, so both halves import it from here.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type BadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
|
13
|
+
export type BadgeSize = 'xs' | 'sm' | 'md' | 'lg'
|
|
14
|
+
|
|
15
|
+
const sizeClasses: Record<string, string> = {
|
|
16
|
+
xs: 'text-[10px] px-1.5 py-0.5',
|
|
17
|
+
sm: 'text-[11px] px-2 py-0.5',
|
|
18
|
+
md: 'text-[12px] px-2.5 py-0.5',
|
|
19
|
+
lg: 'text-[13px] px-3 py-1'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const solidVariants: Record<string, string> = {
|
|
23
|
+
default: 'bg-black/[0.06] text-neutral-600 dark:bg-white/10 dark:text-neutral-300',
|
|
24
|
+
primary: 'bg-blue-500/15 text-blue-600 dark:bg-blue-400/20 dark:text-blue-400',
|
|
25
|
+
success: 'bg-green-500/15 text-green-600 dark:bg-green-400/20 dark:text-green-400',
|
|
26
|
+
warning: 'bg-orange-500/15 text-orange-600 dark:bg-orange-400/20 dark:text-orange-400',
|
|
27
|
+
danger: 'bg-red-500/15 text-red-600 dark:bg-red-400/20 dark:text-red-400',
|
|
28
|
+
info: 'bg-cyan-500/15 text-cyan-600 dark:bg-cyan-400/20 dark:text-cyan-400'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const outlineVariants: Record<string, string> = {
|
|
32
|
+
default: 'border border-black/15 text-neutral-600 dark:border-white/20 dark:text-neutral-300',
|
|
33
|
+
primary: 'border border-blue-500/40 text-blue-600 dark:border-blue-400/50 dark:text-blue-400',
|
|
34
|
+
success: 'border border-green-500/40 text-green-600 dark:border-green-400/50 dark:text-green-400',
|
|
35
|
+
warning: 'border border-orange-500/40 text-orange-600 dark:border-orange-400/50 dark:text-orange-400',
|
|
36
|
+
danger: 'border border-red-500/40 text-red-600 dark:border-red-400/50 dark:text-red-400',
|
|
37
|
+
info: 'border border-cyan-500/40 text-cyan-600 dark:border-cyan-400/50 dark:text-cyan-400'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const dotColors: Record<string, string> = {
|
|
41
|
+
default: 'bg-neutral-400 dark:bg-neutral-500',
|
|
42
|
+
primary: 'bg-blue-500 dark:bg-blue-400',
|
|
43
|
+
success: 'bg-green-500 dark:bg-green-400',
|
|
44
|
+
warning: 'bg-orange-500 dark:bg-orange-400',
|
|
45
|
+
danger: 'bg-red-500 dark:bg-red-400',
|
|
46
|
+
info: 'bg-cyan-500 dark:bg-cyan-400'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A prop that arrived as an attribute is a string, so `outline="false"` must
|
|
51
|
+
* not read as on.
|
|
52
|
+
*/
|
|
53
|
+
function flag(value: unknown): boolean {
|
|
54
|
+
return value === true || value === 'true' || value === ''
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function badgeClasses(variant: unknown = 'default', size: unknown = 'sm', rounded: unknown = 'full', outline: unknown = false): string {
|
|
58
|
+
return [
|
|
59
|
+
'inline-flex items-center font-medium tracking-tight',
|
|
60
|
+
'transition-all duration-150',
|
|
61
|
+
sizeClasses[String(size)] ?? sizeClasses.sm,
|
|
62
|
+
rounded === 'full' ? 'rounded-full' : 'rounded-md',
|
|
63
|
+
(flag(outline) ? outlineVariants : solidVariants)[String(variant)] ?? solidVariants.default,
|
|
64
|
+
].join(' ')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function badgeDotClasses(variant: unknown = 'default'): string {
|
|
68
|
+
return `w-1.5 h-1.5 rounded-full mr-1.5 ${dotColors[String(variant)] ?? dotColors.default}`
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function badgeShowsDot(dot: unknown): boolean {
|
|
72
|
+
return flag(dot)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function tokens(...classLists: string[]): string[] {
|
|
76
|
+
return [...new Set(classLists.flatMap(list => list.split(/\s+/)).filter(Boolean))]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const switchedTokens = tokens(
|
|
80
|
+
...Object.values(sizeClasses),
|
|
81
|
+
...Object.values(solidVariants),
|
|
82
|
+
...Object.values(outlineVariants),
|
|
83
|
+
'rounded-full rounded-md',
|
|
84
|
+
)
|
|
85
|
+
const dotTokens = tokens(...Object.values(dotColors))
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The badge's classes as a `:class` object: every class any size, shape or
|
|
89
|
+
* variant can set, each on or off.
|
|
90
|
+
*
|
|
91
|
+
* Not a string. A string `:class` is appended to the classes the element was
|
|
92
|
+
* rendered with, so a badge first painted grey kept the grey classes next to
|
|
93
|
+
* its live ones, and which colour showed depended on stylesheet order. The
|
|
94
|
+
* object form removes what the current props do not want.
|
|
95
|
+
*/
|
|
96
|
+
export function badgeClassToggles(variant?: unknown, size?: unknown, rounded?: unknown, outline?: unknown): Record<string, boolean> {
|
|
97
|
+
const wanted = new Set(badgeClasses(variant, size, rounded, outline).split(/\s+/))
|
|
98
|
+
return Object.fromEntries(switchedTokens.map(token => [token, wanted.has(token)]))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function badgeDotClassToggles(variant?: unknown): Record<string, boolean> {
|
|
102
|
+
const wanted = new Set(badgeDotClasses(variant).split(/\s+/))
|
|
103
|
+
return Object.fromEntries(dotTokens.map(token => [token, wanted.has(token)]))
|
|
104
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { buttonVariantClasses, buttonVariantToggles } from './dashboard-button'
|
|
3
|
+
|
|
4
|
+
// What the browser does with an object `:class`: add the true keys, remove the
|
|
5
|
+
// false ones, leave every other class alone.
|
|
6
|
+
function apply(start: string, toggles: Record<string, boolean>): string[] {
|
|
7
|
+
const list = new Set(start.split(/\s+/).filter(Boolean))
|
|
8
|
+
for (const [token, on] of Object.entries(toggles)) on ? list.add(token) : list.delete(token)
|
|
9
|
+
return [...list].sort()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const sorted = (classes: string) => classes.split(/\s+/).filter(Boolean).sort()
|
|
13
|
+
|
|
14
|
+
describe('dashboard button variant toggles', () => {
|
|
15
|
+
test('a bound variant replaces the first paint\'s colour', () => {
|
|
16
|
+
const base = 'inline-flex items-center h-8'
|
|
17
|
+
const painted = `${base} ${buttonVariantClasses.primary}`
|
|
18
|
+
expect(apply(painted, buttonVariantToggles('danger'))).toEqual(sorted(`${base} ${buttonVariantClasses.danger}`))
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('the caller\'s own classes survive even when a variant uses them too', () => {
|
|
22
|
+
const caller = 'border shadow-sm w-full'
|
|
23
|
+
const painted = `${caller} ${buttonVariantClasses.secondary}`
|
|
24
|
+
const result = apply(painted, buttonVariantToggles('primary', caller))
|
|
25
|
+
for (const token of caller.split(' ')) expect(result).toContain(token)
|
|
26
|
+
expect(result).not.toContain('bg-white/80')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('bare keeps nothing of a variant and an unknown one falls back to primary', () => {
|
|
30
|
+
expect(apply(buttonVariantClasses.success, buttonVariantToggles('bare'))).toEqual([])
|
|
31
|
+
expect(apply('', buttonVariantToggles('nope'))).toEqual(sorted(buttonVariantClasses.primary))
|
|
32
|
+
})
|
|
33
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The colour classes of a dashboard `<Button>` variant.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the button's server render and its client script. The client half
|
|
5
|
+
* exists for callers that bind `:variant` to client state - the migration
|
|
6
|
+
* plan's confirm button turns `danger` when the plan is destructive - which
|
|
7
|
+
* the server render never sees, so the button kept the variant it was first
|
|
8
|
+
* painted with (stacksjs/stacks#3180).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const buttonVariantClasses: Record<string, string> = {
|
|
12
|
+
primary: 'bg-gradient-to-b from-blue-500 to-blue-600 text-white shadow-sm shadow-blue-600/25 hover:from-blue-400 hover:to-blue-500 active:from-blue-600 active:to-blue-700 dark:from-blue-600 dark:to-blue-700 dark:hover:from-blue-500 dark:hover:to-blue-600',
|
|
13
|
+
secondary: 'bg-white/80 dark:bg-white/10 text-neutral-800 dark:text-neutral-100 border border-black/10 dark:border-white/10 shadow-sm hover:bg-white dark:hover:bg-white/15 active:bg-neutral-100 dark:active:bg-white/5',
|
|
14
|
+
outline: 'bg-transparent text-neutral-700 dark:text-neutral-200 border border-black/15 dark:border-white/15 hover:bg-black/5 dark:hover:bg-white/8 active:bg-black/10 dark:active:bg-white/10',
|
|
15
|
+
ghost: 'bg-transparent text-neutral-600 dark:text-neutral-300 hover:bg-black/5 dark:hover:bg-white/8 active:bg-black/10 dark:active:bg-white/12',
|
|
16
|
+
danger: 'bg-gradient-to-b from-red-500 to-red-600 text-white shadow-sm shadow-red-600/25 hover:from-red-400 hover:to-red-500 active:from-red-600 active:to-red-700',
|
|
17
|
+
success: 'bg-gradient-to-b from-green-500 to-green-600 text-white shadow-sm shadow-green-600/25 hover:from-green-400 hover:to-green-500 active:from-green-600 active:to-green-700',
|
|
18
|
+
warning: 'bg-gradient-to-b from-orange-500 to-orange-600 text-white shadow-sm shadow-orange-600/25 hover:from-orange-400 hover:to-orange-500 active:from-orange-600 active:to-orange-700',
|
|
19
|
+
/**
|
|
20
|
+
* No chrome at all: the caller supplies every visual through `class`.
|
|
21
|
+
*
|
|
22
|
+
* For an affordance that has to sit inside someone else's layout and carry
|
|
23
|
+
* no box of its own - a sortable table header fills its `<th>`, and the
|
|
24
|
+
* padding and fixed height the sizes impose would change the header row.
|
|
25
|
+
* What it still gets, and the reason to come through this component rather
|
|
26
|
+
* than write a raw `<button>`, is the shared focus-visible ring, the
|
|
27
|
+
* disabled and aria-disabled handling, and the press feedback.
|
|
28
|
+
* See stacksjs/stacks#2926.
|
|
29
|
+
*/
|
|
30
|
+
bare: ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The variant's classes as a `:class` object: every class any variant sets,
|
|
35
|
+
* each on or off, so a live change removes the first paint's colour instead
|
|
36
|
+
* of stacking on it. Classes the caller passed in `class` are left alone even
|
|
37
|
+
* when a variant also uses them.
|
|
38
|
+
*/
|
|
39
|
+
export function buttonVariantToggles(variant: unknown, callerClass: unknown = ''): Record<string, boolean> {
|
|
40
|
+
const own = new Set(String(callerClass || '').split(/\s+/).filter(Boolean))
|
|
41
|
+
const wanted = new Set((buttonVariantClasses[String(variant)] ?? buttonVariantClasses.primary).split(/\s+/).filter(Boolean))
|
|
42
|
+
const all = new Set(Object.values(buttonVariantClasses).flatMap(list => list.split(/\s+/)).filter(Boolean))
|
|
43
|
+
return Object.fromEntries([...all].filter(token => !own.has(token)).map(token => [token, wanted.has(token)]))
|
|
44
|
+
}
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.475",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.475",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@iconify-json/f7": "^1.2.2",
|
|
47
47
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
48
|
-
"@stacksjs/mobile": "0.75.
|
|
49
|
-
"@stacksjs/sanitizer": "0.2.
|
|
50
|
-
"@stacksjs/stx": "0.2.
|
|
48
|
+
"@stacksjs/mobile": "0.75.475",
|
|
49
|
+
"@stacksjs/sanitizer": "0.2.800",
|
|
50
|
+
"@stacksjs/stx": "0.2.800",
|
|
51
51
|
"@xterm/addon-fit": "^0.11.0",
|
|
52
52
|
"@xterm/xterm": "^6.0.0",
|
|
53
53
|
"ts-qr-codes": "^0.1.8"
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
import { loadDiscoveredManifest } from '@stacksjs/defaults/resources/functions/dashboard/sidebar'
|
|
3
|
+
|
|
4
|
+
// The Commerce card follows the sidebar's commerce section: with the feature
|
|
5
|
+
// off its models are never loaded, so the page it opens could only answer
|
|
6
|
+
// 503 (stacksjs/stacks#3183).
|
|
7
|
+
export const commerceAnalytics = loadDiscoveredManifest().sections.commerce
|
|
8
|
+
</script>
|
|
9
|
+
|
|
1
10
|
<script client>
|
|
2
11
|
import type { AnalyticsOverview } from '../../../../functions/analytics'
|
|
3
12
|
import { fetchWebAnalytics } from '../../../../functions/analytics'
|
|
@@ -17,7 +26,7 @@ const analyticsCards = [
|
|
|
17
26
|
{ name: 'Countries', description: 'Geographic data when provided', icon: 'i-hugeicons-globe-02', to: '/analytics/countries' },
|
|
18
27
|
{ name: 'Devices', description: 'Device classes from user agents', icon: 'i-hugeicons-smart-phone-01', to: '/analytics/devices' },
|
|
19
28
|
{ name: 'Browsers', description: 'Browser families from user agents', icon: 'i-hugeicons-browser', to: '/analytics/browsers' },
|
|
20
|
-
]
|
|
29
|
+
].filter(card => commerceAnalytics || !card.to.startsWith('/analytics/commerce/'))
|
|
21
30
|
|
|
22
31
|
function formatNumber(value: number | undefined): string {
|
|
23
32
|
return new Intl.NumberFormat().format(value || 0)
|
|
@@ -239,7 +239,7 @@ onMount(() => {
|
|
|
239
239
|
</div>
|
|
240
240
|
<label class="block relative w-full sm:w-72">
|
|
241
241
|
<span class="sr-only">Search {{ page().title.toLowerCase() }}</span>
|
|
242
|
-
<span class="
|
|
242
|
+
<span aria-hidden="true" class="absolute left-3 top-1/2 h-4 w-4 text-neutral-400 pointer-events-none -translate-y-1/2 i-hugeicons-search-01"></span>
|
|
243
243
|
<input x-model="search" type="search" :placeholder="'Search ' + page().title.toLowerCase()" class="block pl-9 pr-3 py-2 w-full text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-neutral-300 rounded-lg dark:border-neutral-700 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20">
|
|
244
244
|
</label>
|
|
245
245
|
</div>
|
|
@@ -41,7 +41,7 @@ function listClass(): string {
|
|
|
41
41
|
<div class="px-4 py-2 bg-white dark:bg-neutral-700 border-b border-gray-200 dark:border-neutral-600">
|
|
42
42
|
<label for="inbox-search" class="sr-only">Search messages</label>
|
|
43
43
|
<div class="relative">
|
|
44
|
-
<span class="
|
|
44
|
+
<span aria-hidden="true" class="absolute left-3 top-1/2 h-4 w-4 text-gray-400 pointer-events-none -translate-y-1/2 i-hugeicons-search-01"></span>
|
|
45
45
|
<input id="inbox-search" x-model="search" type="search" placeholder="Search messages" class="block placeholder-gray-500 dark:placeholder-gray-400 pl-10 pr-3 py-2 w-full text-gray-900 text-sm dark:text-neutral-100 bg-gray-50 dark:bg-neutral-600 border border-gray-300 rounded-md dark:border-neutral-600 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" @input="emit('search', $event.target.value)" />
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
@@ -57,9 +57,12 @@ function handlePanelClick(event: MouseEvent): void {
|
|
|
57
57
|
closeSidebar()
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// Widening past the breakpoint closes the drawer the same way a tap does, so
|
|
61
|
+
// the scroll lock is released and the layout gets its `close` to take its
|
|
62
|
+
// sidebar back. Setting the state alone did neither.
|
|
60
63
|
effect(() => {
|
|
61
64
|
if (isDesktop() && isOpen())
|
|
62
|
-
|
|
65
|
+
closeSidebar()
|
|
63
66
|
})
|
|
64
67
|
|
|
65
68
|
useEventListener('keydown', handleKeydown)
|
|
@@ -141,7 +141,7 @@ onMount(() => {
|
|
|
141
141
|
<div class="flex flex-col gap-2 sm:flex-row w-full sm:w-auto">
|
|
142
142
|
<label class="block relative w-full sm:w-64">
|
|
143
143
|
<span class="sr-only">Search models</span>
|
|
144
|
-
<span class="
|
|
144
|
+
<span aria-hidden="true" class="absolute left-3 top-1/2 h-4 w-4 text-neutral-400 pointer-events-none -translate-y-1/2 i-hugeicons-search-01"></span>
|
|
145
145
|
<input x-model="search" type="search" placeholder="Search models" class="block pl-9 pr-3 py-2 w-full text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-900 border border-neutral-300 rounded-lg dark:border-neutral-700 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20">
|
|
146
146
|
</label>
|
|
147
147
|
<label>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script server>
|
|
2
|
+
import { badgeClasses, badgeDotClasses } from '../../../../functions/dashboard-badge'
|
|
3
|
+
|
|
2
4
|
interface BadgeProps {
|
|
3
5
|
variant?: 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
|
4
6
|
size?: 'xs' | 'sm' | 'md' | 'lg'
|
|
@@ -14,53 +16,28 @@ const { variant = 'default', size = 'sm', rounded = 'full', outline = false, dot
|
|
|
14
16
|
// `{{ text }}` rendered the validator function source into every Badge.
|
|
15
17
|
// Use the slot for the badge label instead.
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const solidVariants = {
|
|
25
|
-
default: 'bg-black/[0.06] text-neutral-600 dark:bg-white/10 dark:text-neutral-300',
|
|
26
|
-
primary: 'bg-blue-500/15 text-blue-600 dark:bg-blue-400/20 dark:text-blue-400',
|
|
27
|
-
success: 'bg-green-500/15 text-green-600 dark:bg-green-400/20 dark:text-green-400',
|
|
28
|
-
warning: 'bg-orange-500/15 text-orange-600 dark:bg-orange-400/20 dark:text-orange-400',
|
|
29
|
-
danger: 'bg-red-500/15 text-red-600 dark:bg-red-400/20 dark:text-red-400',
|
|
30
|
-
info: 'bg-cyan-500/15 text-cyan-600 dark:bg-cyan-400/20 dark:text-cyan-400'
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const outlineVariants = {
|
|
34
|
-
default: 'border border-black/15 text-neutral-600 dark:border-white/20 dark:text-neutral-300',
|
|
35
|
-
primary: 'border border-blue-500/40 text-blue-600 dark:border-blue-400/50 dark:text-blue-400',
|
|
36
|
-
success: 'border border-green-500/40 text-green-600 dark:border-green-400/50 dark:text-green-400',
|
|
37
|
-
warning: 'border border-orange-500/40 text-orange-600 dark:border-orange-400/50 dark:text-orange-400',
|
|
38
|
-
danger: 'border border-red-500/40 text-red-600 dark:border-red-400/50 dark:text-red-400',
|
|
39
|
-
info: 'border border-cyan-500/40 text-cyan-600 dark:border-cyan-400/50 dark:text-cyan-400'
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const dotColors = {
|
|
43
|
-
default: 'bg-neutral-400 dark:bg-neutral-500',
|
|
44
|
-
primary: 'bg-blue-500 dark:bg-blue-400',
|
|
45
|
-
success: 'bg-green-500 dark:bg-green-400',
|
|
46
|
-
warning: 'bg-orange-500 dark:bg-orange-400',
|
|
47
|
-
danger: 'bg-red-500 dark:bg-red-400',
|
|
48
|
-
info: 'bg-cyan-500 dark:bg-cyan-400'
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const badgeClass = [
|
|
52
|
-
'inline-flex items-center font-medium tracking-tight',
|
|
53
|
-
'transition-all duration-150',
|
|
54
|
-
sizeClasses[size],
|
|
55
|
-
rounded === 'full' ? 'rounded-full' : 'rounded-md',
|
|
56
|
-
outline ? outlineVariants[variant] : solidVariants[variant]
|
|
57
|
-
].join(' ')
|
|
19
|
+
// The first paint. The client script keeps both in step afterwards.
|
|
20
|
+
const badgeClass = badgeClasses(variant, size, rounded, outline)
|
|
21
|
+
const dotClass = badgeDotClasses(variant)
|
|
22
|
+
</script>
|
|
23
|
+
<script client>
|
|
24
|
+
import { badgeClassToggles, badgeDotClassToggles, badgeShowsDot } from '../../../../functions/dashboard-badge'
|
|
58
25
|
|
|
59
|
-
|
|
26
|
+
// Read live as well: callers bind `:variant` to data that arrives after
|
|
27
|
+
// hydration, and the value the server render saw never changed
|
|
28
|
+
// (stacksjs/stacks#3179).
|
|
29
|
+
const liveVariant = useReactiveProp('variant', 'default')
|
|
30
|
+
const liveSize = useReactiveProp('size', 'sm')
|
|
31
|
+
const liveRounded = useReactiveProp('rounded', 'full')
|
|
32
|
+
const liveOutline = useReactiveProp('outline', false)
|
|
33
|
+
const liveDot = useReactiveProp('dot', false)
|
|
34
|
+
const liveBadgeClass = derived(() => badgeClassToggles(liveVariant(), liveSize(), liveRounded(), liveOutline()))
|
|
35
|
+
const liveDotClass = derived(() => badgeDotClassToggles(liveVariant()))
|
|
36
|
+
const showDot = derived(() => badgeShowsDot(liveDot()))
|
|
60
37
|
</script>
|
|
61
|
-
<span class="{{ badgeClass }}">
|
|
38
|
+
<span class="{{ badgeClass }}" :class="liveBadgeClass()">
|
|
62
39
|
@if(dot)
|
|
63
|
-
<span class="{{ dotClass }}"></span>
|
|
40
|
+
<span class="{{ dotClass }}" :class="liveDotClass()" :if="showDot()"></span>
|
|
64
41
|
@endif
|
|
65
42
|
<slot />
|
|
66
43
|
</span>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script server>
|
|
2
|
+
import { buttonVariantClasses } from '../../../../functions/dashboard-button'
|
|
3
|
+
|
|
2
4
|
interface ButtonProps {
|
|
3
5
|
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'success' | 'warning' | 'bare'
|
|
4
6
|
size?: 'xs' | 'sm' | 'md' | 'lg'
|
|
@@ -32,29 +34,6 @@ const {
|
|
|
32
34
|
href = '',
|
|
33
35
|
} = defineProps<ButtonProps>()
|
|
34
36
|
|
|
35
|
-
// Variant classes
|
|
36
|
-
const variantClasses = {
|
|
37
|
-
primary: 'bg-gradient-to-b from-blue-500 to-blue-600 text-white shadow-sm shadow-blue-600/25 hover:from-blue-400 hover:to-blue-500 active:from-blue-600 active:to-blue-700 dark:from-blue-600 dark:to-blue-700 dark:hover:from-blue-500 dark:hover:to-blue-600',
|
|
38
|
-
secondary: 'bg-white/80 dark:bg-white/10 text-neutral-800 dark:text-neutral-100 border border-black/10 dark:border-white/10 shadow-sm hover:bg-white dark:hover:bg-white/15 active:bg-neutral-100 dark:active:bg-white/5',
|
|
39
|
-
outline: 'bg-transparent text-neutral-700 dark:text-neutral-200 border border-black/15 dark:border-white/15 hover:bg-black/5 dark:hover:bg-white/8 active:bg-black/10 dark:active:bg-white/10',
|
|
40
|
-
ghost: 'bg-transparent text-neutral-600 dark:text-neutral-300 hover:bg-black/5 dark:hover:bg-white/8 active:bg-black/10 dark:active:bg-white/12',
|
|
41
|
-
danger: 'bg-gradient-to-b from-red-500 to-red-600 text-white shadow-sm shadow-red-600/25 hover:from-red-400 hover:to-red-500 active:from-red-600 active:to-red-700',
|
|
42
|
-
success: 'bg-gradient-to-b from-green-500 to-green-600 text-white shadow-sm shadow-green-600/25 hover:from-green-400 hover:to-green-500 active:from-green-600 active:to-green-700',
|
|
43
|
-
warning: 'bg-gradient-to-b from-orange-500 to-orange-600 text-white shadow-sm shadow-orange-600/25 hover:from-orange-400 hover:to-orange-500 active:from-orange-600 active:to-orange-700',
|
|
44
|
-
/**
|
|
45
|
-
* No chrome at all: the caller supplies every visual through `class`.
|
|
46
|
-
*
|
|
47
|
-
* For an affordance that has to sit inside someone else's layout and carry
|
|
48
|
-
* no box of its own - a sortable table header fills its `<th>`, and the
|
|
49
|
-
* padding and fixed height the sizes impose would change the header row.
|
|
50
|
-
* What it still gets, and the reason to come through this component rather
|
|
51
|
-
* than write a raw `<button>`, is the shared focus-visible ring, the
|
|
52
|
-
* disabled and aria-disabled handling, and the press feedback.
|
|
53
|
-
* See stacksjs/stacks#2926.
|
|
54
|
-
*/
|
|
55
|
-
bare: ''
|
|
56
|
-
}
|
|
57
|
-
|
|
58
37
|
// Size classes
|
|
59
38
|
const sizeClasses = {
|
|
60
39
|
xs: 'text-[11px] px-2 py-1 rounded-md gap-1 h-6',
|
|
@@ -85,10 +64,17 @@ const buttonClass = [
|
|
|
85
64
|
fullWidth ? 'w-full' : '',
|
|
86
65
|
// `bare` takes neither: its whole point is to impose no box.
|
|
87
66
|
variant === 'bare' ? '' : (iconOnly ? iconOnlySizes[size] : sizeClasses[size]),
|
|
88
|
-
|
|
67
|
+
buttonVariantClasses[variant]
|
|
89
68
|
].filter(Boolean).join(' ')
|
|
90
69
|
</script>
|
|
91
70
|
<script client>
|
|
71
|
+
import { buttonVariantToggles } from '../../../../functions/dashboard-button'
|
|
72
|
+
|
|
73
|
+
// A bound `:variant` changes after the server render; the toggles move the
|
|
74
|
+
// colour with it (stacksjs/stacks#3180).
|
|
75
|
+
const liveVariant = useReactiveProp('variant', 'primary')
|
|
76
|
+
const liveCallerClass = useReactiveProp('class', '')
|
|
77
|
+
const variantToggles = derived(() => buttonVariantToggles(liveVariant(), liveCallerClass()))
|
|
92
78
|
const liveDisabled = useReactiveProp('disabled', false)
|
|
93
79
|
const liveLoading = useReactiveProp('loading', false)
|
|
94
80
|
const livePressed = useReactiveProp('pressed', false)
|
|
@@ -117,6 +103,7 @@ const liveAriaExpanded = useReactiveProp('ariaExpanded', '')
|
|
|
117
103
|
:download="liveDownload() || undefined"
|
|
118
104
|
:aria-label="liveAriaLabel() || undefined"
|
|
119
105
|
class="{{ buttonClass }}"
|
|
106
|
+
:class="variantToggles()"
|
|
120
107
|
:target="liveTarget() || undefined"
|
|
121
108
|
:rel="liveRel() || undefined"
|
|
122
109
|
:aria-busy="liveLoading() ? 'true' : 'false'"
|
|
@@ -134,6 +121,7 @@ const liveAriaExpanded = useReactiveProp('ariaExpanded', '')
|
|
|
134
121
|
:type="liveType()"
|
|
135
122
|
:form="liveForm() || undefined"
|
|
136
123
|
class="{{ buttonClass }}"
|
|
124
|
+
:class="variantToggles()"
|
|
137
125
|
:aria-label="liveAriaLabel() || undefined"
|
|
138
126
|
:aria-busy="liveLoading() ? 'true' : 'false'"
|
|
139
127
|
:aria-pressed="String(livePressed())"
|
|
@@ -149,6 +137,7 @@ const liveAriaExpanded = useReactiveProp('ariaExpanded', '')
|
|
|
149
137
|
:type="liveType()"
|
|
150
138
|
:form="liveForm() || undefined"
|
|
151
139
|
class="{{ buttonClass }}"
|
|
140
|
+
:class="variantToggles()"
|
|
152
141
|
:aria-label="liveAriaLabel() || undefined"
|
|
153
142
|
:aria-haspopup="liveAriaHasPopup() || undefined"
|
|
154
143
|
:aria-expanded="liveAriaExpanded() || undefined"
|
|
@@ -56,6 +56,12 @@ const cardClass = [
|
|
|
56
56
|
clickableClass,
|
|
57
57
|
].join(' ')
|
|
58
58
|
</script>
|
|
59
|
+
<script client>
|
|
60
|
+
// A bound `:subtitle` is empty when the card renders on the server, so the
|
|
61
|
+
// line above never rendered at all; this one follows the value once it
|
|
62
|
+
// arrives (stacksjs/stacks#3180). A static subtitle still paints first.
|
|
63
|
+
const liveSubtitle = useReactiveProp('subtitle', '')
|
|
64
|
+
</script>
|
|
59
65
|
|
|
60
66
|
<article class="{{ cardClass }}" @if(clickable) role="button" tabindex="0" @endif>
|
|
61
67
|
@if($slots.header)
|
|
@@ -70,6 +76,8 @@ const cardClass = [
|
|
|
70
76
|
@endif
|
|
71
77
|
@if(subtitle)
|
|
72
78
|
<p class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">{{ subtitle }}</p>
|
|
79
|
+
@else
|
|
80
|
+
<p :if="liveSubtitle()" class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">{{ liveSubtitle() }}</p>
|
|
73
81
|
@endif
|
|
74
82
|
</div>
|
|
75
83
|
@if($slots.actions)
|
|
@@ -471,7 +471,9 @@ export function buildNavSections(
|
|
|
471
471
|
{ to: '/marketing/social-posts', icon: 'clock', text: 'Social Posts' },
|
|
472
472
|
{ to: '/marketing/campaigns', icon: 'rocket', text: 'Campaigns' },
|
|
473
473
|
{ to: '/marketing/abandoned-carts', icon: 'cart', text: 'Abandoned Carts' },
|
|
474
|
-
|
|
474
|
+
// Product reviews are commerce records, so with commerce off this page
|
|
475
|
+
// could only say so (stacksjs/stacks#3186).
|
|
476
|
+
...(toggles.commerce ? [{ to: '/marketing/reviews', icon: 'star', text: 'Reviews' }] : []),
|
|
475
477
|
...categoryNavItems(discoveredModels, 'marketing', new Set(['campaign'])),
|
|
476
478
|
]])
|
|
477
479
|
}
|
|
@@ -491,8 +493,15 @@ export function buildNavSections(
|
|
|
491
493
|
{ to: '/analytics/browsers', icon: 'globe', text: 'Browsers' },
|
|
492
494
|
{ to: '/analytics/events', icon: 'bolt', text: 'Events' },
|
|
493
495
|
{ to: '/analytics/blog', icon: 'document', text: 'Blog' },
|
|
494
|
-
|
|
495
|
-
|
|
496
|
+
// Commerce's analytics follow the commerce section. With the feature
|
|
497
|
+
// off its models are never loaded, so Sales could only answer 503
|
|
498
|
+
// (stacksjs/stacks#3183).
|
|
499
|
+
...(toggles.commerce
|
|
500
|
+
? [
|
|
501
|
+
{ to: '/analytics/commerce/web', icon: 'cart', text: 'Commerce' },
|
|
502
|
+
{ to: '/analytics/commerce/sales', icon: 'sale-tag', text: 'Sales' },
|
|
503
|
+
]
|
|
504
|
+
: []),
|
|
496
505
|
{ to: '/analytics/marketing', icon: 'megaphone', text: 'Marketing' },
|
|
497
506
|
]])
|
|
498
507
|
}
|
|
@@ -129,6 +129,20 @@ body {
|
|
|
129
129
|
left: var(--stx-sidebar-width, 250px);
|
|
130
130
|
transition: left 0.3s ease-out;
|
|
131
131
|
}
|
|
132
|
+
/*
|
|
133
|
+
* The window's sidebar pane while it is in the mobile drawer: it fills the
|
|
134
|
+
* drawer instead of sitting fixed at its window width, and gives up the
|
|
135
|
+
* window's z-index so the drawer's close button stays on top of it.
|
|
136
|
+
*/
|
|
137
|
+
[data-dashboard-mobile-sidebar] > [data-stx-component-wrapper] {
|
|
138
|
+
height: 100%;
|
|
139
|
+
}
|
|
140
|
+
[data-dashboard-mobile-sidebar] [data-stx-sidebar] {
|
|
141
|
+
position: relative;
|
|
142
|
+
z-index: auto;
|
|
143
|
+
width: 100% !important;
|
|
144
|
+
height: 100%;
|
|
145
|
+
}
|
|
132
146
|
@media (max-width: 1023px) {
|
|
133
147
|
[data-stx-content] {
|
|
134
148
|
margin-left: 0;
|
|
@@ -589,11 +603,34 @@ function handleSidebarItemClick(payload: { item?: { href?: string }, event?: { p
|
|
|
589
603
|
navigate(href)
|
|
590
604
|
}
|
|
591
605
|
|
|
592
|
-
|
|
606
|
+
// Where the Sidebar sat in the window while it is lent to the drawer.
|
|
607
|
+
let lentSidebar: { element: HTMLElement, parent: Node, next: Node | null } | null = null
|
|
608
|
+
|
|
609
|
+
// The Sidebar's component wrapper moves, not just its pane: the wrapper is
|
|
610
|
+
// where the layout's `@itemClick` listens, so a pane moved without it kept
|
|
611
|
+
// selecting rows but never navigated.
|
|
612
|
+
function showSidebarInDrawer() {
|
|
613
|
+
const pane = sidebarHost.current?.querySelector<HTMLElement>('[data-stx-sidebar]')
|
|
614
|
+
const element = pane?.closest<HTMLElement>('[data-stx-component-wrapper]') ?? pane
|
|
615
|
+
const drawer = mobileSidebarHost.current
|
|
616
|
+
if (element?.parentNode && drawer && !lentSidebar) {
|
|
617
|
+
lentSidebar = { element, parent: element.parentNode, next: element.nextSibling }
|
|
618
|
+
drawer.appendChild(element)
|
|
619
|
+
}
|
|
593
620
|
applyRoleFilter()
|
|
594
621
|
syncActiveSidebarRow()
|
|
595
622
|
}
|
|
596
623
|
|
|
624
|
+
// Back where it came from, before anything else looks for it. The drawer's
|
|
625
|
+
// markup is already gone by now, so the Sidebar is put back from the
|
|
626
|
+
// reference kept above rather than looked up.
|
|
627
|
+
function returnSidebarFromDrawer() {
|
|
628
|
+
if (!lentSidebar) return
|
|
629
|
+
const { element, parent, next } = lentSidebar
|
|
630
|
+
lentSidebar = null
|
|
631
|
+
parent.insertBefore(element, next && next.parentNode === parent ? next : null)
|
|
632
|
+
}
|
|
633
|
+
|
|
597
634
|
function handleCraftSidebarSelection(event: CraftSidebarSelectEvent | undefined): void {
|
|
598
635
|
if (!event?.itemId) return
|
|
599
636
|
for (const pane of sidebarPanes()) {
|
|
@@ -658,23 +695,11 @@ onDestroy(() => {
|
|
|
658
695
|
</Sidebar>
|
|
659
696
|
</div>
|
|
660
697
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
width="320"
|
|
667
|
-
placement="static"
|
|
668
|
-
className="h-full max-w-full"
|
|
669
|
-
@itemClick="handleSidebarItemClick($event)"
|
|
670
|
-
>
|
|
671
|
-
<template #header>
|
|
672
|
-
<!-- A drawer, not the window edge: no window buttons land on it, so
|
|
673
|
-
there is nothing to draw and nothing to reserve. -->
|
|
674
|
-
<SidebarHeader windowControls="none" />
|
|
675
|
-
</template>
|
|
676
|
-
</Sidebar>
|
|
677
|
-
</div>
|
|
698
|
+
<!-- The drawer holds the same Sidebar as the window, moved in while it is open
|
|
699
|
+
(`showSidebarInDrawer`). A second Sidebar here rendered all its rows again
|
|
700
|
+
on every page and doubled each page's first render (stacksjs/stacks#3177). -->
|
|
701
|
+
<MobileSidebar @open="showSidebarInDrawer()" @close="returnSidebarFromDrawer()">
|
|
702
|
+
<div ref="dashboardMobileSidebarHost" data-dashboard-mobile-sidebar class="h-full"></div>
|
|
678
703
|
</MobileSidebar>
|
|
679
704
|
|
|
680
705
|
<main data-stx-content>
|