@stacksjs/defaults 0.75.229 → 0.75.231
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-dashboard/SKILL.md +15 -0
- package/ai/skills/stacks-dependencies/SKILL.md +12 -6
- package/ai/skills/stacks-models/SKILL.md +6 -1
- package/ai/skills/stacks-native/CATALOG.md +4 -4
- package/app/Actions/Dashboard/Models/GetModels.ts +19 -14
- package/app/Actions/Dashboard/Models/GetSubscriberCount.ts +5 -2
- package/app/Actions/Dashboard/Models/GetUserCount.ts +5 -2
- package/app/Actions/Dashboard/Models/ModelShowAction.ts +3 -11
- package/app/Actions/Dashboard/Models/ModelsIndexAction.ts +6 -3
- package/app/Actions/Dashboard/Models/model-write.ts +2 -3
- package/app/Actions/Dashboard/Search/GlobalSearchAction.ts +6 -2
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/resources/functions/dashboard/model-access.ts +15 -0
- package/resources/plugins/preloader.ts +3 -0
|
@@ -652,3 +652,18 @@ or a fake success response.
|
|
|
652
652
|
- Preserve the existing sidebar information architecture and styling when redesigning page content
|
|
653
653
|
- Use `dashboard-modal-layer` for every fixed dashboard dialog or drawer
|
|
654
654
|
- The live terminal component polls real deployment output and pauses while the document is hidden
|
|
655
|
+
|
|
656
|
+
## Generic model exposure
|
|
657
|
+
|
|
658
|
+
Set `dashboard: { access: false }` on a model to exclude it server-side from
|
|
659
|
+
the generic model catalog and its totals, legacy highlighted model counts,
|
|
660
|
+
User/Subscriber count Actions, global model search, and generic model-browser
|
|
661
|
+
read/store/update/destroy Actions. Direct model-browser requests return 404
|
|
662
|
+
before row queries. Omission preserves existing exposure.
|
|
663
|
+
|
|
664
|
+
`dashboard.enabled: false` only hides a sidebar row and still permits generic
|
|
665
|
+
model access. `access` does not disable direct ORM calls, named domain Actions,
|
|
666
|
+
or separate routes generated by `useApi`. Configure `security.api.models` or
|
|
667
|
+
`STACKS_MODEL_APIS`, middleware, ownership and policies for those APIs. The
|
|
668
|
+
new boundary does not provide row ownership or permission checks for models
|
|
669
|
+
that remain exposed.
|
|
@@ -104,13 +104,19 @@ A Stacks project commits two lockfiles, and they describe one tree:
|
|
|
104
104
|
**and** every npm package, which `pantry/` holds and the framework source
|
|
105
105
|
resolves from.
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
Pantry follows `bun.lock`'s pin when it satisfies the declared npm range, so
|
|
108
|
+
shared npm records must agree. Native platform records can differ between
|
|
109
|
+
hosts. Review the generated difference and use the repository's lock guards:
|
|
110
|
+
an allowed platform addition does not excuse a missing or changed declared
|
|
111
|
+
dependency, stale workspace ranges, or a lost system-toolchain block.
|
|
112
|
+
|
|
113
|
+
**Regenerating.** Use the repository's declared, Pantry-managed Bun. Change the
|
|
114
|
+
ranges, run `bun install`, then `pantry install --ignore-scripts --quiet`, and
|
|
115
|
+
commit both lockfiles with the manifests. This is the metadata-only mode the
|
|
116
|
+
framework release action uses. A plain `pantry install` can activate project
|
|
117
|
+
services and run `postDatabaseSetup` or `postSetup` hooks, including migrations
|
|
118
|
+
and seeding; those are separate from maintaining dependency locks.
|
|
111
119
|
|
|
112
|
-
**Regenerating.** Change the ranges, run `bun install`, then `pantry install`,
|
|
113
|
-
on any platform, and commit `bun.lock` and `pantry.lock` with the manifests.
|
|
114
120
|
Check `head -2 bun.lock` says `lockfileVersion: 2`; an older Bun on PATH
|
|
115
121
|
downgrades it.
|
|
116
122
|
|
|
@@ -123,7 +123,12 @@ of forcing a cast. See `orm/tests/inference-attributes.test-d.ts`.
|
|
|
123
123
|
|
|
124
124
|
Also at the top level: `indexes: [{ name, columns, unique?, where? }]` for
|
|
125
125
|
composite and partial-unique indexes, and `dashboard: { highlight: true }` to
|
|
126
|
-
feature the model in the admin UI.
|
|
126
|
+
feature the model in the admin UI. Use `dashboard: { access: false }` to
|
|
127
|
+
exclude a model from generic dashboard catalogs/counts/search and the generic
|
|
128
|
+
model-browser CRUD Actions before database work. Its default is `true`;
|
|
129
|
+
`dashboard.enabled: false` still only hides the sidebar row. `access` leaves
|
|
130
|
+
direct ORM calls, named domain Actions and generated `useApi` routes available.
|
|
131
|
+
Those APIs require their own route selection, middleware, ownership and policies.
|
|
127
132
|
|
|
128
133
|
`useApi` is an API capability, not a dashboard-view generator. Its generated
|
|
129
134
|
routes are registered from the merged model registry. Framework defaults are
|
|
@@ -11,7 +11,7 @@ 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) | 73 |
|
|
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) | 17 |
|
|
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 |
|
|
@@ -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) | 118 |
|
|
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) | 151 |
|
|
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) | 2 |
|
|
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) | 11 |
|
|
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 |
|
|
@@ -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/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/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: [73 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
|
|
|
@@ -215,7 +215,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
|
|
|
215
215
|
|
|
216
216
|
Local source modules: [src/commands/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/commands/index.ts).
|
|
217
217
|
|
|
218
|
-
Evidence directory: [
|
|
218
|
+
Evidence directory: [151 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.
|
|
219
219
|
|
|
220
220
|
### @stacksjs/build
|
|
221
221
|
|
|
@@ -3,6 +3,7 @@ import { Glob } from 'bun'
|
|
|
3
3
|
import { Action } from '@stacksjs/actions/runtime'
|
|
4
4
|
import { path } from '@stacksjs/path'
|
|
5
5
|
import { countRows } from '../../../../resources/functions/dashboard/data'
|
|
6
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
6
7
|
import { dashboardOperationalError } from '../dashboard-response'
|
|
7
8
|
|
|
8
9
|
export default new Action({
|
|
@@ -16,23 +17,27 @@ export default new Action({
|
|
|
16
17
|
const scanOptions = { cwd: path.userModelsPath(), onlyFiles: true }
|
|
17
18
|
const displayModels: Model[] = []
|
|
18
19
|
|
|
19
|
-
for await (const file of glob.scan(scanOptions)) {
|
|
20
|
-
const model = (await import(path.userModelsPath(file))).default as Model
|
|
21
|
-
if (model.dashboard?.highlight !== undefined && model.dashboard?.highlight !== false)
|
|
22
|
-
displayModels.push(model)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!displayModels.length) {
|
|
26
|
-
// If no models should be highlighted, we can just return up to 8 models in alphabetical order
|
|
27
20
|
for await (const file of glob.scan(scanOptions)) {
|
|
28
|
-
const
|
|
29
|
-
|
|
21
|
+
const candidate = (await import(path.userModelsPath(file))).default as Model
|
|
22
|
+
const model = await resolveDashboardModel(candidate.name || '', candidate)
|
|
23
|
+
if (!model) continue
|
|
24
|
+
if (model.dashboard?.highlight !== undefined && model.dashboard?.highlight !== false)
|
|
25
|
+
displayModels.push(model)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!displayModels.length) {
|
|
29
|
+
// If no models should be highlighted, return up to 8 accessible models.
|
|
30
|
+
for await (const file of glob.scan(scanOptions)) {
|
|
31
|
+
const candidate = (await import(path.userModelsPath(file))).default as Model
|
|
32
|
+
const model = await resolveDashboardModel(candidate.name || '', candidate)
|
|
33
|
+
if (!model) continue
|
|
34
|
+
displayModels.push(model)
|
|
35
|
+
}
|
|
30
36
|
}
|
|
31
|
-
}
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
if (displayModels.length > 8)
|
|
39
|
+
displayModels.length = 8
|
|
40
|
+
displayModels.sort((a, b) => (a.name || '').localeCompare(b.name || ''))
|
|
36
41
|
|
|
37
42
|
return await Promise.all(displayModels.map(async model => ({
|
|
38
43
|
model: model.name,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions/runtime'
|
|
2
|
-
import {
|
|
2
|
+
import { response } from '@stacksjs/router'
|
|
3
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
3
4
|
import { dashboardOperationalError } from '../dashboard-response'
|
|
4
5
|
|
|
5
6
|
export default new Action({
|
|
@@ -10,7 +11,9 @@ export default new Action({
|
|
|
10
11
|
|
|
11
12
|
async handle() {
|
|
12
13
|
try {
|
|
13
|
-
|
|
14
|
+
const Model = await resolveDashboardModel('Subscriber')
|
|
15
|
+
if (!Model) return response.json({ message: 'Model not found.' }, 404)
|
|
16
|
+
return await Model.count()
|
|
14
17
|
}
|
|
15
18
|
catch (error) {
|
|
16
19
|
return dashboardOperationalError(error, 'Subscriber total could not be loaded.', 'GetSubscriberCount')
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions/runtime'
|
|
2
|
-
import {
|
|
2
|
+
import { response } from '@stacksjs/router'
|
|
3
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
3
4
|
import { dashboardOperationalError } from '../dashboard-response'
|
|
4
5
|
|
|
5
6
|
export default new Action({
|
|
@@ -10,7 +11,9 @@ export default new Action({
|
|
|
10
11
|
|
|
11
12
|
async handle() {
|
|
12
13
|
try {
|
|
13
|
-
|
|
14
|
+
const Model = await resolveDashboardModel('User')
|
|
15
|
+
if (!Model) return response.json({ message: 'Model not found.' }, 404)
|
|
16
|
+
return await Model.count()
|
|
14
17
|
}
|
|
15
18
|
catch (error) {
|
|
16
19
|
return dashboardOperationalError(error, 'User total could not be loaded.', 'GetUserCount')
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { RequestInstance } from '@stacksjs/types'
|
|
2
2
|
import { Action } from '@stacksjs/actions/runtime'
|
|
3
3
|
import { response as routerResponse } from '@stacksjs/router'
|
|
4
|
-
import {
|
|
4
|
+
import { safeGet } from '../../../../resources/functions/dashboard/data'
|
|
5
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
5
6
|
import { dashboardOperationalError } from '../dashboard-response'
|
|
6
7
|
import { isValidModelSlug, type ModelCreateField, type ModelWriteCapabilities, modelCreateFields, modelSchemaColumns, modelWritableColumns, modelWriteCapabilities, slugToPascal } from './model-write'
|
|
7
8
|
|
|
@@ -159,15 +160,6 @@ export function parseFilters(raw: string | null): Record<string, string> {
|
|
|
159
160
|
return out
|
|
160
161
|
}
|
|
161
162
|
|
|
162
|
-
function resolveOrmModel(modelName: string): any {
|
|
163
|
-
const injected = (globalThis as Record<string, any>)[modelName]
|
|
164
|
-
// The ORM injects Proxies that answer `undefined` for every property
|
|
165
|
-
// until their deferred load lands, so probe for a real query method
|
|
166
|
-
// rather than trusting the name to be bound.
|
|
167
|
-
if (injected && typeof injected.where === 'function') return injected
|
|
168
|
-
return null
|
|
169
|
-
}
|
|
170
|
-
|
|
171
163
|
export default new Action({
|
|
172
164
|
name: 'Dashboard Model Show',
|
|
173
165
|
description: 'Queries a single model by URL slug with paging, sorting, search and column filters.',
|
|
@@ -221,7 +213,7 @@ export default new Action({
|
|
|
221
213
|
|
|
222
214
|
let Model: any
|
|
223
215
|
try {
|
|
224
|
-
Model =
|
|
216
|
+
Model = await resolveDashboardModel(modelName)
|
|
225
217
|
}
|
|
226
218
|
catch (error) {
|
|
227
219
|
return dashboardOperationalError(error, `${modelName} could not be loaded.`, 'ModelShowAction.resolve')
|
|
@@ -4,6 +4,7 @@ import { join } from 'node:path'
|
|
|
4
4
|
import process from 'node:process'
|
|
5
5
|
import { countRows } from '../../../../resources/functions/dashboard/data'
|
|
6
6
|
import { dashboardOperationalError, dashboardOperationalIssue } from '../dashboard-response'
|
|
7
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
7
8
|
import { modelApiConfiguration } from './model-api'
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -127,7 +128,7 @@ export default new Action({
|
|
|
127
128
|
let userland: Array<Omit<DiscoveredModel, 'source'>>
|
|
128
129
|
let defaults: Array<Omit<DiscoveredModel, 'source'>>
|
|
129
130
|
try {
|
|
130
|
-
userland = walkModels(userlandDir,
|
|
131
|
+
userland = walkModels(userlandDir, true)
|
|
131
132
|
defaults = walkModels(defaultsDir, true)
|
|
132
133
|
}
|
|
133
134
|
catch (error) {
|
|
@@ -144,11 +145,12 @@ export default new Action({
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
const
|
|
148
|
+
const candidates = await Promise.all(merged.map(async (m): Promise<ModelRow | null> => {
|
|
148
149
|
let Model: any
|
|
149
150
|
try {
|
|
150
151
|
const module = await import(m.file)
|
|
151
|
-
Model = module.default ?? module
|
|
152
|
+
Model = await resolveDashboardModel(m.name, module.default ?? module)
|
|
153
|
+
if (!Model) return null
|
|
152
154
|
}
|
|
153
155
|
catch (error) {
|
|
154
156
|
return unavailableModelRow(
|
|
@@ -190,6 +192,7 @@ export default new Action({
|
|
|
190
192
|
}
|
|
191
193
|
}))
|
|
192
194
|
|
|
195
|
+
const enriched = candidates.filter((model): model is ModelRow => model !== null)
|
|
193
196
|
enriched.sort((a, b) => a.name.localeCompare(b.name))
|
|
194
197
|
|
|
195
198
|
const totalModels = enriched.length
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* casts and no observers; writing to it from a generic admin screen would
|
|
7
7
|
* bypass every guarantee the ORM makes. Those rows stay read-only.
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
10
10
|
import { dashboardOperationalIssue } from '../dashboard-response'
|
|
11
11
|
import { modelApiConfiguration } from './model-api'
|
|
12
12
|
|
|
@@ -301,10 +301,9 @@ export async function resolveWritableModel(slug: string, operation?: ModelWriteO
|
|
|
301
301
|
return { error: 'Model slug must be lowercase kebab-case.', status: 400 }
|
|
302
302
|
|
|
303
303
|
const modelName = slugToPascal(slug)
|
|
304
|
-
const injected = (globalThis as Record<string, any>)[modelName]
|
|
305
304
|
let Model: any
|
|
306
305
|
try {
|
|
307
|
-
Model =
|
|
306
|
+
Model = await resolveDashboardModel(modelName)
|
|
308
307
|
}
|
|
309
308
|
catch (error) {
|
|
310
309
|
return {
|
|
@@ -4,6 +4,7 @@ import { env } from '@stacksjs/env'
|
|
|
4
4
|
import { readdirSync } from 'node:fs'
|
|
5
5
|
import { basename, extname, join } from 'node:path'
|
|
6
6
|
import process from 'node:process'
|
|
7
|
+
import { resolveDashboardModel } from '../../../../resources/functions/dashboard/model-access'
|
|
7
8
|
import { dashboardOperationalError } from '../dashboard-response'
|
|
8
9
|
|
|
9
10
|
interface SearchableModel {
|
|
@@ -126,7 +127,8 @@ async function loadSearchableModels(): Promise<SearchableModel[]> {
|
|
|
126
127
|
for (const [fallbackName, file] of merged) {
|
|
127
128
|
try {
|
|
128
129
|
const module = await import(file)
|
|
129
|
-
const definition = module.default ?? module
|
|
130
|
+
const definition = await resolveDashboardModel(fallbackName, module.default ?? module)
|
|
131
|
+
if (!definition) continue
|
|
130
132
|
const name = String(definition.name || fallbackName)
|
|
131
133
|
const search = definition.traits?.useSearch
|
|
132
134
|
if (!search || typeof search !== 'object' || !Array.isArray(search.searchable)) continue
|
|
@@ -197,13 +199,15 @@ export default new Action({
|
|
|
197
199
|
if (!q) return { results: {} }
|
|
198
200
|
|
|
199
201
|
try {
|
|
202
|
+
const models = await catalog()
|
|
203
|
+
if (models.length === 0) return { results: {}, unavailable: [] }
|
|
200
204
|
const { Database } = await import('bun:sqlite')
|
|
201
205
|
const db = new Database(env.DB_DATABASE_PATH || 'database/stacks.sqlite', { readonly: true })
|
|
202
206
|
const results: Record<string, SearchResult[]> = {}
|
|
203
207
|
const unavailable: SearchUnavailable[] = []
|
|
204
208
|
|
|
205
209
|
try {
|
|
206
|
-
for (const model of
|
|
210
|
+
for (const model of models) {
|
|
207
211
|
if (Object.keys(results).length >= MAX_GROUPS) break
|
|
208
212
|
|
|
209
213
|
const columns = db.query(`PRAGMA table_info(${model.table})`).all() as Array<{ name: string }>
|
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.231",
|
|
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.231",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@iconify-json/f7": "^1.2.2",
|
|
46
46
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
47
|
-
"@stacksjs/mobile": "0.75.
|
|
47
|
+
"@stacksjs/mobile": "0.75.231",
|
|
48
48
|
"@stacksjs/sanitizer": "^0.2.534",
|
|
49
49
|
"@xterm/addon-fit": "^0.11.0",
|
|
50
50
|
"@xterm/xterm": "^6.0.0",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Server-side exposure boundary for the generic dashboard model surfaces. */
|
|
2
|
+
import type { DashboardModelOptions } from '@stacksjs/types'
|
|
3
|
+
import { loadModelIfExists } from './data'
|
|
4
|
+
|
|
5
|
+
/** Omission preserves the existing dashboard exposure. `enabled` only controls navigation. */
|
|
6
|
+
export function hasDashboardModelAccess(Model: { dashboard?: DashboardModelOptions } | null | undefined): boolean {
|
|
7
|
+
return Model?.dashboard?.access !== false
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Resolve the native model, then exclude it before callers inspect metadata or query rows. */
|
|
11
|
+
export async function resolveDashboardModel(name: string, candidate?: any): Promise<any | null> {
|
|
12
|
+
const injected = (globalThis as Record<string, any>)[name]
|
|
13
|
+
const Model = (injected && typeof injected.where === 'function') ? injected : (candidate ?? await loadModelIfExists(name))
|
|
14
|
+
return Model && hasDashboardModelAccess(Model) ? Model : null
|
|
15
|
+
}
|