@stacksjs/defaults 0.75.337 → 0.75.341
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-native/CATALOG.md +12 -12
- package/ai/skills/stacks-router/SKILL.md +25 -0
- package/app/Actions/Dashboard/Remote/remote-terminal.test.ts +66 -16
- package/app/Actions/Dashboard/Remote/remote-terminal.ts +8 -2
- package/app/Actions/Dashboard/Remote/terminal-sessions.ts +5 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/resources/components/Dashboard/Auth/AccessTokens.stx +2 -2
- package/resources/components/Dashboard/Remote/RemoteConsole.stx +23 -1
|
@@ -11,8 +11,8 @@ 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) |
|
|
15
|
-
| `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/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) | 91 |
|
|
15
|
+
| `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 18 |
|
|
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) | 1 |
|
|
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) | 6 |
|
|
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) | 9 |
|
|
@@ -21,7 +21,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
21
21
|
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 120 |
|
|
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) | 8 |
|
|
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) | 7 |
|
|
24
|
-
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) |
|
|
24
|
+
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 170 |
|
|
25
25
|
| `@stacksjs/build` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/build/src/index.ts) | 4 |
|
|
26
26
|
| `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 14 |
|
|
27
27
|
| `@stacksjs/calendar-api` | [`stacks-calendar`](../stacks-calendar/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/index.ts) | 2 |
|
|
@@ -68,14 +68,14 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
68
68
|
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 73 |
|
|
69
69
|
| `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
|
|
70
70
|
| `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 13 |
|
|
71
|
-
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) |
|
|
71
|
+
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 30 |
|
|
72
72
|
| `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 6 |
|
|
73
73
|
| `@stacksjs/query-builder` | [`stacks-query-builder`](../stacks-query-builder/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/query-builder/src/index.ts) | 6 |
|
|
74
74
|
| `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 49 |
|
|
75
75
|
| `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 12 |
|
|
76
76
|
| `@stacksjs/registry` | [`stacks-registry`](../stacks-registry/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/registry/src/index.ts) | 1 |
|
|
77
77
|
| `@stacksjs/repl` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/repl/src/index.ts) | 2 |
|
|
78
|
-
| `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) |
|
|
78
|
+
| `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 97 |
|
|
79
79
|
| `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 14 |
|
|
80
80
|
| `@stacksjs/search-engine` | [`stacks-search-engine`](../stacks-search-engine/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/search-engine/src/index.ts) | 11 |
|
|
81
81
|
| `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 11 |
|
|
@@ -119,7 +119,7 @@ Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT
|
|
|
119
119
|
|
|
120
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/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).
|
|
121
121
|
|
|
122
|
-
Evidence directory: [
|
|
122
|
+
Evidence directory: [91 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
|
|
|
@@ -127,9 +127,9 @@ Guidance: [`stacks-ai`](../stacks-ai/SKILL.md). Source: [storage/framework/core/
|
|
|
127
127
|
|
|
128
128
|
Declared runtime exports: `assistantTurn`, `buildMessageWithImages`, `clearUsageReporters`, `estimateMessageTokens`, `estimateTokens`, `fetchWithRetry`, `listUsageReporters`, `normalizeMessagesForProvider`, `onUsage`, `recordUsage`, `sanitizePrompt`, `toolResultsTurn`.
|
|
129
129
|
|
|
130
|
-
Local source modules: [src/agents/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/agents/index.ts), [src/buddy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/buddy.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/client.ts), [src/context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/context.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/drivers/index.ts), [src/image.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/image.ts), [src/mcp-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp-server.ts), [src/mcp.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp.ts), [src/models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/models.ts), [src/personalization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/personalization.ts), [src/search.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/search.ts), [src/speech.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/speech.ts), [src/text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/text.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/types.ts), [src/utils/client-bedrock-runtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock-runtime.ts), [src/utils/client-bedrock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock.ts), [src/utils/model-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/model-access.ts), [src/utils/retry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/retry.ts), [src/utils/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tokens.ts), [src/utils/tools.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tools.ts), [src/utils/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/usage.ts), [src/utils/vision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/vision.ts).
|
|
130
|
+
Local source modules: [src/agents/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/agents/index.ts), [src/buddy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/buddy.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/client.ts), [src/context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/context.ts), [src/documents.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/documents.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/drivers/index.ts), [src/image.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/image.ts), [src/mcp-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp-server.ts), [src/mcp.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp.ts), [src/models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/models.ts), [src/personalization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/personalization.ts), [src/search.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/search.ts), [src/speech.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/speech.ts), [src/text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/text.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/types.ts), [src/utils/client-bedrock-runtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock-runtime.ts), [src/utils/client-bedrock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock.ts), [src/utils/model-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/model-access.ts), [src/utils/retry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/retry.ts), [src/utils/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tokens.ts), [src/utils/tools.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tools.ts), [src/utils/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/usage.ts), [src/utils/vision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/vision.ts).
|
|
131
131
|
|
|
132
|
-
Evidence directory: [
|
|
132
|
+
Evidence directory: [18 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
133
133
|
|
|
134
134
|
### @stacksjs/alias
|
|
135
135
|
|
|
@@ -217,7 +217,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
|
|
|
217
217
|
|
|
218
218
|
Local source modules: [src/commands/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/commands/index.ts).
|
|
219
219
|
|
|
220
|
-
Evidence directory: [
|
|
220
|
+
Evidence directory: [170 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
221
221
|
|
|
222
222
|
### @stacksjs/build
|
|
223
223
|
|
|
@@ -661,7 +661,7 @@ Declared runtime exports: `Payment`, `freshIdempotencyKey`, `stacksIdempotencyKe
|
|
|
661
661
|
|
|
662
662
|
Local source modules: [src/billable/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/billable/index.ts), [src/checkout-outcome.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/checkout-outcome.ts), [src/connect/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/connect/index.ts), [src/direct-debit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/direct-debit.ts), [src/driver/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/driver/index.ts), [src/drivers/stripe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/drivers/stripe.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/idempotency.ts), [src/payment.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/payment.ts), [src/subscription-state.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/subscription-state.ts), [src/terminal.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/terminal.ts).
|
|
663
663
|
|
|
664
|
-
Evidence directory: [
|
|
664
|
+
Evidence directory: [30 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
665
665
|
|
|
666
666
|
### @stacksjs/push
|
|
667
667
|
|
|
@@ -721,11 +721,11 @@ Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/m
|
|
|
721
721
|
|
|
722
722
|
Guidance: [`stacks-router`](../stacks-router/SKILL.md). Source: [storage/framework/core/router/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts).
|
|
723
723
|
|
|
724
|
-
Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRedisConnection`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `clientAddress`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `fallbackStorage`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRedirectRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `parseJsonText`, `rateLimit`, `rateLimitScale`, `rateLimitStatus`, `readJsonBody`, `readTextBody`, `request`, `resetBootHooks`, `resetRateLimiters`, `resetSharedRateLimitStorage`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `scaledLimit`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `sharedRateLimitStorage`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `trustedProxies`, `url`, `useRateLimitStorage`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withRouteAdmission`, `withTraceId`, `wrapAction`.
|
|
724
|
+
Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRedisConnection`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `clientAddress`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `fallbackStorage`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRedirectRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `parseJsonText`, `rateLimit`, `rateLimitScale`, `rateLimitStatus`, `readJsonBody`, `readTextBody`, `request`, `resetBootHooks`, `resetRateLimiters`, `resetSharedRateLimitStorage`, `resetShutdownHooks`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runShutdownHooks`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `scaledLimit`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `sharedRateLimitStorage`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `trustedProxies`, `url`, `useRateLimitStorage`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withRouteAdmission`, `withTraceId`, `wrapAction`.
|
|
725
725
|
|
|
726
726
|
Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/body.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/body.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/json.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/json.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/security-settings.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/security-settings.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
|
|
727
727
|
|
|
728
|
-
Evidence directory: [
|
|
728
|
+
Evidence directory: [97 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
729
729
|
|
|
730
730
|
### @stacksjs/scheduler
|
|
731
731
|
|
|
@@ -417,6 +417,31 @@ await serve({ port: 3000 })
|
|
|
417
417
|
const response = await serverResponse(request)
|
|
418
418
|
```
|
|
419
419
|
|
|
420
|
+
### Boot and shutdown hooks
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
import { route } from '@stacksjs/router'
|
|
424
|
+
|
|
425
|
+
// Once, after the routes load and before the first request. Optional
|
|
426
|
+
// preparation only: a hook that throws is logged and the boot continues.
|
|
427
|
+
route.booting('warm grammars', () => highlighter.load())
|
|
428
|
+
|
|
429
|
+
// When the server is told to stop. For whatever would otherwise outlive the
|
|
430
|
+
// process or end unrecorded: open sessions, child processes, a buffer to flush.
|
|
431
|
+
route.stopping('terminal sessions', () => terminalSessions.closeAll())
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
- Boot hooks run in order, once per process, from `serve()`.
|
|
435
|
+
- Shutdown hooks run concurrently, once per process (a second signal waits on
|
|
436
|
+
the same run). One that throws is logged and the rest still run.
|
|
437
|
+
- The production API server (`core/actions/src/serve/api.ts`) runs them on
|
|
438
|
+
SIGTERM alongside draining in-flight requests. `SHUTDOWN_GRACE_MS` (default
|
|
439
|
+
fifteen seconds) caps both, so a hook that hangs cannot hold the process.
|
|
440
|
+
- The list lives on `globalThis`, so a module registering through a second copy
|
|
441
|
+
of `@stacksjs/router` still reaches the one the server runs.
|
|
442
|
+
- `buddy dev:api` has no shutdown handler: Ctrl-C ends the process group, and
|
|
443
|
+
shutdown hooks do not run there.
|
|
444
|
+
|
|
420
445
|
## URL Generation
|
|
421
446
|
|
|
422
447
|
```typescript
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { UserModel } from '@stacksjs/orm'
|
|
2
2
|
import type { RemoteHost } from './remote-commands'
|
|
3
3
|
import type { TerminalAuditSink, TerminalEvent, TerminalProcess, TerminalSessionOptions } from './remote-terminal'
|
|
4
|
-
import { describe, expect, it } from 'bun:test'
|
|
5
|
-
import { existsSync
|
|
4
|
+
import { describe, expect, it, jest } from 'bun:test'
|
|
5
|
+
import { existsSync } from 'node:fs'
|
|
6
6
|
import { tmpdir } from 'node:os'
|
|
7
|
+
import { dirname } from 'node:path'
|
|
7
8
|
import { sshTerminalArgv } from './remote-commands'
|
|
8
9
|
import { TerminalSessions } from './remote-terminal'
|
|
9
10
|
import { createPtySpawner } from './ssh-runner'
|
|
10
|
-
import { encodeTerminalEvent, terminalEventStream } from './terminal-sessions'
|
|
11
|
+
import { encodeTerminalEvent, terminalEventStream, terminalSessions } from './terminal-sessions'
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Interactive terminal sessions (stacksjs/stacks#960). Every rule is asserted
|
|
@@ -236,16 +237,28 @@ describe('a session does not outlive its purpose', () => {
|
|
|
236
237
|
})
|
|
237
238
|
|
|
238
239
|
it('input keeps it alive; the max duration ends it regardless', async () => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
// The clock is driven, not slept on: the deadlines under test run on the
|
|
241
|
+
// same clock a sleep waits on, so under load a sleep overshot them (#2978).
|
|
242
|
+
jest.useFakeTimers()
|
|
243
|
+
try {
|
|
244
|
+
const { manager, fakes, audit } = sessions({ idleTimeoutMs: 40, maxDurationMs: 120, detachGraceMs: 10_000 })
|
|
245
|
+
const { id } = await manager.open({ user: alice, hosts, hostKey: 'app', authorizer: allowAll, cols: 80, rows: 24 })
|
|
246
|
+
for (let i = 0; i < 4; i++) {
|
|
247
|
+
jest.advanceTimersByTime(25)
|
|
248
|
+
await manager.input(id, alice, 'x')
|
|
249
|
+
}
|
|
250
|
+
const ending = take(manager.watch(id, alice), 1)
|
|
251
|
+
// 119ms in: more than twice the idle timeout, kept open by the input.
|
|
252
|
+
jest.advanceTimersByTime(19)
|
|
253
|
+
expect(fakes[0]!.killed).toBe(false)
|
|
254
|
+
jest.advanceTimersByTime(1)
|
|
255
|
+
expect(fakes[0]!.killed).toBe(true)
|
|
256
|
+
expect((await ending).map(text)).toEqual(['<max-duration>'])
|
|
257
|
+
expect(audit.log.at(-1)).toStartWith('closed max-duration')
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
jest.useRealTimers()
|
|
244
261
|
}
|
|
245
|
-
expect(fakes[0]!.killed).toBe(false)
|
|
246
|
-
await Bun.sleep(60)
|
|
247
|
-
expect(fakes[0]!.killed).toBe(true)
|
|
248
|
-
expect(audit.log.at(-1)).toStartWith('closed max-duration')
|
|
249
262
|
})
|
|
250
263
|
|
|
251
264
|
it('ends when nobody attaches, and a grace period after the last viewer leaves', async () => {
|
|
@@ -272,6 +285,40 @@ describe('a session does not outlive its purpose', () => {
|
|
|
272
285
|
await expect(manager.close(id, alice)).rejects.toThrow('No such terminal session')
|
|
273
286
|
expect(audit.log.slice(1)).toEqual(['input rm -rf /tmp/build', 'closed closed in=17 out=0'])
|
|
274
287
|
})
|
|
288
|
+
|
|
289
|
+
it('shuts down only once every process has exited, so nothing it made outlives it', async () => {
|
|
290
|
+
// The real spawner removes its temp directory when the process exits; a
|
|
291
|
+
// shutdown that returned on the kill raced the process exiting (#2978).
|
|
292
|
+
let exit!: (code: number) => void
|
|
293
|
+
const { manager } = sessions({
|
|
294
|
+
spawn: () => ({ write: () => {}, resize: () => {}, kill: () => {}, exited: new Promise<number>((resolve) => { exit = resolve }) }),
|
|
295
|
+
})
|
|
296
|
+
await manager.open({ user: alice, hosts, hostKey: 'app', authorizer: allowAll, cols: 80, rows: 24 })
|
|
297
|
+
|
|
298
|
+
const closing = manager.closeAll().then(() => 'closed')
|
|
299
|
+
expect(await Promise.race([closing, Bun.sleep(20).then(() => 'waiting')])).toBe('waiting')
|
|
300
|
+
exit(-1)
|
|
301
|
+
expect(await closing).toBe('closed')
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it('is closed by the server stopping, through the router\'s shutdown hooks (#3034)', async () => {
|
|
305
|
+
const registered = (globalThis as Record<symbol, { hooks: Array<{ name: string, run: () => unknown }> }>)[Symbol.for('@stacksjs/router:shutdown-hooks')]
|
|
306
|
+
const hook = registered?.hooks.find(entry => entry.name === 'terminal sessions')
|
|
307
|
+
expect(hook).toBeDefined()
|
|
308
|
+
|
|
309
|
+
// The app's own sessions, not a copy: the hook has to reach the manager
|
|
310
|
+
// the terminal actions open sessions on.
|
|
311
|
+
const closeAll = terminalSessions.closeAll
|
|
312
|
+
let closed = 0
|
|
313
|
+
terminalSessions.closeAll = async () => { closed += 1 }
|
|
314
|
+
try {
|
|
315
|
+
await hook!.run()
|
|
316
|
+
}
|
|
317
|
+
finally {
|
|
318
|
+
terminalSessions.closeAll = closeAll
|
|
319
|
+
}
|
|
320
|
+
expect(closed).toBe(1)
|
|
321
|
+
})
|
|
275
322
|
})
|
|
276
323
|
|
|
277
324
|
describe('the event stream', () => {
|
|
@@ -304,7 +351,6 @@ describe('the PTY spawner', () => {
|
|
|
304
351
|
})
|
|
305
352
|
|
|
306
353
|
it('carries output, input and a window resize through a real PTY, and cleans up', async () => {
|
|
307
|
-
const before = readdirSync(tmpdir()).filter(name => name.startsWith('stacks-terminal-')).length
|
|
308
354
|
let knownHosts = ''
|
|
309
355
|
const spawn = createPtySpawner((_host, path) => {
|
|
310
356
|
knownHosts = path
|
|
@@ -315,7 +361,10 @@ describe('the PTY spawner', () => {
|
|
|
315
361
|
const process = await spawn(shellHost, { cols: 100, rows: 30 }, (bytes) => { output += new TextDecoder().decode(bytes) })
|
|
316
362
|
expect(existsSync(knownHosts)).toBe(true)
|
|
317
363
|
|
|
318
|
-
|
|
364
|
+
// Resize once the shell has reported the size it started at, not after a
|
|
365
|
+
// guess at how long that takes.
|
|
366
|
+
for (let i = 0; i < 200 && !output.includes('30 100'); i++)
|
|
367
|
+
await Bun.sleep(10)
|
|
319
368
|
process.resize(132, 40)
|
|
320
369
|
process.write('hello\r')
|
|
321
370
|
expect(await process.exited).toBe(0)
|
|
@@ -324,8 +373,9 @@ describe('the PTY spawner', () => {
|
|
|
324
373
|
expect(output).toContain('30 100')
|
|
325
374
|
expect(output).toContain('40 132')
|
|
326
375
|
expect(output).toContain('got:hello')
|
|
327
|
-
|
|
328
|
-
|
|
376
|
+
// The directory this spawn created, not a count of the shared temp
|
|
377
|
+
// directory, which other processes change underneath the test (#2978).
|
|
378
|
+
expect(existsSync(dirname(knownHosts))).toBe(false)
|
|
329
379
|
})
|
|
330
380
|
})
|
|
331
381
|
|
|
@@ -261,9 +261,15 @@ export class TerminalSessions {
|
|
|
261
261
|
await this.end(this.find(id, user), 'closed')
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
/**
|
|
264
|
+
/**
|
|
265
|
+
* End every session, for a server shutting down, and wait for each process
|
|
266
|
+
* to exit: the spawner cleans up after the process, and a server that exits
|
|
267
|
+
* first leaves that behind.
|
|
268
|
+
*/
|
|
265
269
|
async closeAll(): Promise<void> {
|
|
266
|
-
|
|
270
|
+
const open = [...this.sessions.values()]
|
|
271
|
+
await Promise.all(open.map(session => this.end(session, 'shutdown')))
|
|
272
|
+
await Promise.all(open.map(session => session.process.exited))
|
|
267
273
|
}
|
|
268
274
|
|
|
269
275
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TerminalAuthorizer, TerminalEvent } from './remote-terminal'
|
|
2
2
|
import { Gate } from '@stacksjs/auth'
|
|
3
|
+
import { route } from '@stacksjs/router'
|
|
3
4
|
import { TerminalSessions } from './remote-terminal'
|
|
4
5
|
import { createPtySpawner, loggingTerminalAuditSink } from './ssh-runner'
|
|
5
6
|
|
|
@@ -18,6 +19,10 @@ export const terminalSessions: TerminalSessions = new TerminalSessions({
|
|
|
18
19
|
audit: loggingTerminalAuditSink,
|
|
19
20
|
})
|
|
20
21
|
|
|
22
|
+
// A server that stops closes its sessions first, so each one records why it
|
|
23
|
+
// ended and its temp directory goes with its process (stacksjs/stacks#3034).
|
|
24
|
+
route.stopping('terminal sessions', () => terminalSessions.closeAll())
|
|
25
|
+
|
|
21
26
|
/**
|
|
22
27
|
* The `open-remote-terminal` gate, or undefined when the app has not defined
|
|
23
28
|
* it - and `TerminalSessions.open` refuses in that case rather than proceeding.
|
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.341",
|
|
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.341",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@iconify-json/f7": "^1.2.2",
|
|
47
47
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
48
|
-
"@stacksjs/mobile": "0.75.
|
|
48
|
+
"@stacksjs/mobile": "0.75.341",
|
|
49
49
|
"@stacksjs/sanitizer": "0.2.736",
|
|
50
50
|
"@stacksjs/stx": "0.2.736",
|
|
51
51
|
"@xterm/addon-fit": "^0.11.0",
|
|
@@ -221,7 +221,7 @@ onMount(() => {
|
|
|
221
221
|
<span class="h-4 w-4 i-hugeicons-key-02"></span>
|
|
222
222
|
Create Token
|
|
223
223
|
</Button>
|
|
224
|
-
<Button :if="!loading() && authenticationRequired()" tag="a" href="/login">
|
|
224
|
+
<Button :if="!loading() && authenticationRequired()" tag="a" href="/login?redirect=/access-tokens">
|
|
225
225
|
<span class="h-4 w-4 i-hugeicons-login-03"></span>
|
|
226
226
|
Sign in
|
|
227
227
|
</Button>
|
|
@@ -271,7 +271,7 @@ onMount(() => {
|
|
|
271
271
|
description="Personal access tokens belong to an authenticated account. Sign in to create, inspect, or revoke them."
|
|
272
272
|
>
|
|
273
273
|
<template #action>
|
|
274
|
-
<Button tag="a" href="/login">
|
|
274
|
+
<Button tag="a" href="/login?redirect=/access-tokens">
|
|
275
275
|
<span class="h-4 w-4 i-hugeicons-login-03"></span>
|
|
276
276
|
Sign in
|
|
277
277
|
</Button>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script client>
|
|
2
2
|
import type { RemoteCommandResult, RemoteRegistry } from '../../../../functions/remote'
|
|
3
|
+
import { DashboardApiError } from '../../../../functions/dashboard-api'
|
|
3
4
|
import { fetchRemoteRegistry, requestRemoteCommand } from '../../../../functions/remote'
|
|
4
5
|
import { registerRemoteTerminal } from '../../../../functions/remote-terminal-element'
|
|
5
6
|
import { pushToast } from '../../../../functions/toasts'
|
|
@@ -9,6 +10,9 @@ void registerRemoteTerminal()
|
|
|
9
10
|
const registry = state<RemoteRegistry | null>(null)
|
|
10
11
|
const isLoading = state(true)
|
|
11
12
|
const loadError = state('')
|
|
13
|
+
// Remote access needs a signed-in account even where the rest of the dev
|
|
14
|
+
// dashboard does not, so a 401 here asks for a sign-in rather than failing.
|
|
15
|
+
const authenticationRequired = state(false)
|
|
12
16
|
const selectedHost = state('')
|
|
13
17
|
const selectedCommand = state('')
|
|
14
18
|
const isRunning = state(false)
|
|
@@ -27,6 +31,7 @@ const commandsForHost = derived(() => {
|
|
|
27
31
|
async function load(): Promise<void> {
|
|
28
32
|
isLoading.set(true)
|
|
29
33
|
loadError.set('')
|
|
34
|
+
authenticationRequired.set(false)
|
|
30
35
|
try {
|
|
31
36
|
const data = await fetchRemoteRegistry()
|
|
32
37
|
registry.set(data)
|
|
@@ -34,7 +39,10 @@ async function load(): Promise<void> {
|
|
|
34
39
|
selectedHost.set(data.hosts[0].key)
|
|
35
40
|
}
|
|
36
41
|
catch (error) {
|
|
37
|
-
|
|
42
|
+
if (error instanceof DashboardApiError && error.status === 401)
|
|
43
|
+
authenticationRequired.set(true)
|
|
44
|
+
else
|
|
45
|
+
loadError.set(error instanceof Error ? error.message : 'The remote hosts could not be loaded.')
|
|
38
46
|
}
|
|
39
47
|
finally {
|
|
40
48
|
isLoading.set(false)
|
|
@@ -87,6 +95,20 @@ onMount(() => {
|
|
|
87
95
|
|
|
88
96
|
<div :if="isLoading()" class="text-gray-500 text-sm dark:text-neutral-400">Loading hosts</div>
|
|
89
97
|
|
|
98
|
+
<EmptyState
|
|
99
|
+
:if="!isLoading() && authenticationRequired()"
|
|
100
|
+
icon="i-hugeicons-user-lock-01"
|
|
101
|
+
title="Sign in to use remote access"
|
|
102
|
+
description="Running commands and opening terminals on your servers needs a signed-in account, in every environment. Each run and session is recorded under it."
|
|
103
|
+
>
|
|
104
|
+
<template #action>
|
|
105
|
+
<Button tag="a" href="/login?redirect=/remote">
|
|
106
|
+
<span class="h-4 w-4 i-hugeicons-login-03"></span>
|
|
107
|
+
Sign in
|
|
108
|
+
</Button>
|
|
109
|
+
</template>
|
|
110
|
+
</EmptyState>
|
|
111
|
+
|
|
90
112
|
<section :if="!isLoading() && registry() && hosts().length === 0" class="p-6 bg-white dark:bg-neutral-800 border border-gray-200 rounded-lg dark:border-neutral-700">
|
|
91
113
|
<h2 class="font-semibold text-gray-900 dark:text-white">No hosts are configured</h2>
|
|
92
114
|
<p class="mt-1 max-w-2xl text-gray-500 text-sm dark:text-neutral-400">
|