@fougere/nuxt 0.4.0-alpha.0 → 0.5.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.ts +29 -2
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +78 -31
- package/dist/module.js.map +1 -1
- package/dist/runtime/composables/useCurrentUser.d.ts +8 -0
- package/dist/runtime/composables/useCurrentUser.d.ts.map +1 -0
- package/dist/runtime/composables/useCurrentUser.js +21 -0
- package/dist/runtime/composables/useCurrentUser.js.map +1 -0
- package/dist/runtime/composables/useFormFor.d.ts +27 -0
- package/dist/runtime/composables/useFormFor.d.ts.map +1 -0
- package/dist/runtime/composables/useFormFor.js +76 -0
- package/dist/runtime/composables/useFormFor.js.map +1 -0
- package/dist/runtime/composables/useFougereData.d.ts +21 -0
- package/dist/runtime/composables/useFougereData.d.ts.map +1 -0
- package/dist/runtime/composables/useFougereData.js +74 -0
- package/dist/runtime/composables/useFougereData.js.map +1 -0
- package/dist/runtime/plugins/session.server.d.ts +3 -0
- package/dist/runtime/plugins/session.server.d.ts.map +1 -0
- package/dist/runtime/plugins/session.server.js +13 -0
- package/dist/runtime/plugins/session.server.js.map +1 -0
- package/dist/runtime/server/api/crud.d.ts +3 -0
- package/dist/runtime/server/api/crud.d.ts.map +1 -0
- package/dist/runtime/server/api/crud.js +46 -0
- package/dist/runtime/server/api/crud.js.map +1 -0
- package/dist/runtime/server/auth/middleware/auth.d.ts +7 -0
- package/dist/runtime/server/auth/middleware/auth.d.ts.map +1 -0
- package/dist/runtime/server/auth/middleware/auth.js +32 -0
- package/dist/runtime/server/auth/middleware/auth.js.map +1 -0
- package/dist/runtime/server/auth/routes/api/me.get.d.ts +5 -0
- package/dist/runtime/server/auth/routes/api/me.get.d.ts.map +1 -0
- package/dist/runtime/server/auth/routes/api/me.get.js +10 -0
- package/dist/runtime/server/auth/routes/api/me.get.js.map +1 -0
- package/dist/runtime/server/auth/routes/auth/[...].d.ts +3 -0
- package/dist/runtime/server/auth/routes/auth/[...].d.ts.map +1 -0
- package/dist/runtime/server/auth/routes/auth/[...].js +8 -0
- package/dist/runtime/server/auth/routes/auth/[...].js.map +1 -0
- package/dist/runtime/server/routes/call.post.d.ts +3 -0
- package/dist/runtime/server/routes/call.post.d.ts.map +1 -0
- package/dist/runtime/server/routes/call.post.js +125 -0
- package/dist/runtime/server/routes/call.post.js.map +1 -0
- package/dist/runtime/server/routes/session.get.d.ts +3 -0
- package/dist/runtime/server/routes/session.get.d.ts.map +1 -0
- package/dist/runtime/server/routes/session.get.js +9 -0
- package/dist/runtime/server/routes/session.get.js.map +1 -0
- package/dist/runtime/server/utils/boot.d.ts +13 -0
- package/dist/runtime/server/utils/boot.d.ts.map +1 -0
- package/dist/runtime/server/utils/boot.js +13 -0
- package/dist/runtime/server/utils/boot.js.map +1 -0
- package/dist/runtime/server/utils/invoke.d.ts +9 -0
- package/dist/runtime/server/utils/invoke.d.ts.map +1 -0
- package/dist/runtime/server/utils/invoke.js +24 -0
- package/dist/runtime/server/utils/invoke.js.map +1 -0
- package/package.json +6 -6
- package/src/module.ts +98 -28
- package/src/runtime/composables/useFougereData.ts +11 -1
- package/src/runtime/server/auth/routes/auth/[...].ts +1 -1
- package/src/runtime/server/routes/call.post.ts +1 -1
- package/src/shims.d.ts +7 -0
package/src/module.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import type { Nuxt } from '@nuxt/schema';
|
|
18
18
|
import { orderSeeds } from '@fougere/core';
|
|
19
19
|
import {
|
|
20
|
-
scanProject,
|
|
20
|
+
scanProject, emitStatement, frondAliases, frondPackage, watchPathsOf, resolveConventions, type Conventions,
|
|
21
21
|
setModuleLoader, loadCascadedConfig,
|
|
22
22
|
} from '@fougere/core/node';
|
|
23
23
|
import { declaresStorage } from '@fougere/defaults';
|
|
@@ -35,6 +35,40 @@ export interface FougereModuleOptions {
|
|
|
35
35
|
* fronds are shared at the root. Config and `.fougere` stay app-local.
|
|
36
36
|
*/
|
|
37
37
|
root?: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* One key per EXTENSION, and the key is the package suffix AND the export name —
|
|
41
|
+
* `calls` is `import { calls } from '@fougere/calls'`. So the module holds no table to
|
|
42
|
+
* keep in step with the packages, the same rule the scan applies to `@fronds/<name>`.
|
|
43
|
+
*
|
|
44
|
+
* An extension is a FUNCTION and this module writes a FILE, so a project cannot pass one
|
|
45
|
+
* here: it names one, and the options travel beside it as data.
|
|
46
|
+
*
|
|
47
|
+
* The keys are declared rather than left open on purpose. An open record would derive
|
|
48
|
+
* everything and accept `callz: {}` in silence — the failure this repo already records
|
|
49
|
+
* for `adapters:`, which "fails OPEN, giving neither completion nor a guard". The price
|
|
50
|
+
* is that a new extension package adds a key here.
|
|
51
|
+
*/
|
|
52
|
+
/** `@fougere/observability` — a span per operation, the four signals, OTLP. */
|
|
53
|
+
observability?: Record<string, unknown> | false;
|
|
54
|
+
/** `@fougere/calls` — the dev panel: a bounded log of what this process dispatched. */
|
|
55
|
+
calls?: Record<string, unknown> | false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The extension keys, in the order they are mounted.
|
|
60
|
+
*
|
|
61
|
+
* A list and not the options object's own keys: the ORDER is ours, not the project's.
|
|
62
|
+
* `observability` installs the middleware that opens the span every log line written
|
|
63
|
+
* inside a call will carry — mounted the other way round, the lines leave uncorrelated.
|
|
64
|
+
*/
|
|
65
|
+
const EXTENSION_KEYS = ['observability', 'calls'] as const;
|
|
66
|
+
|
|
67
|
+
/** What the project asked for, in mount order. `false` is how a key is turned off. */
|
|
68
|
+
export function extensionsOf(options: FougereModuleOptions): { key: string; options: unknown }[] {
|
|
69
|
+
return EXTENSION_KEYS
|
|
70
|
+
.filter((key) => options[key] !== undefined && options[key] !== false)
|
|
71
|
+
.map((key) => ({ key, options: options[key] }));
|
|
38
72
|
}
|
|
39
73
|
|
|
40
74
|
|
|
@@ -54,7 +88,7 @@ const module = defineNuxtModule<FougereModuleOptions>({
|
|
|
54
88
|
async setup(options: FougereModuleOptions, nuxt: Nuxt) {
|
|
55
89
|
const { resolve: resolveModule } = createResolver(import.meta.url);
|
|
56
90
|
const runtimeResolve = (...path: string[]) =>
|
|
57
|
-
resolveModule('
|
|
91
|
+
resolveModule('./runtime', ...path);
|
|
58
92
|
const rootDir = nuxt.options.rootDir;
|
|
59
93
|
// Fronds may live at the workspace root (app under apps/*); config/.fougere stay app-local.
|
|
60
94
|
const scanRoot = options.root ? resolve(rootDir, options.root) : rootDir;
|
|
@@ -242,29 +276,43 @@ const module = defineNuxtModule<FougereModuleOptions>({
|
|
|
242
276
|
});
|
|
243
277
|
}
|
|
244
278
|
|
|
245
|
-
// ── 6.
|
|
279
|
+
// ── 6. What this app hosts ───
|
|
246
280
|
//
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
// diagnostics say why. One scan, one value, handed to the boot.
|
|
281
|
+
// A `fronds.ts` beside `fougere.config.ts` is the app STATING it — the same shape
|
|
282
|
+
// `configureFougere({ fronds })` gives every other host, made where the author can
|
|
283
|
+
// make it. The scan still runs at build and stays a CHECK: its diagnostics reach the
|
|
284
|
+
// console, and it becomes no module.
|
|
252
285
|
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
286
|
+
// Nothing is generated, because a generated module was imported by ABSOLUTE path,
|
|
287
|
+
// which a bundler sees as `file://` and therefore external. Externalized, Node read
|
|
288
|
+
// the frond's `.ts` itself — stripping types but resolving `../entities/Post.js`
|
|
289
|
+
// literally, a file that is not on disk. Measured on demos/nuxt-blog in-process:
|
|
290
|
+
// 500 on every call in `nuxt dev`, 200 once the statement is the only source.
|
|
291
|
+
// A codegen inside one repo also had nothing to carry: `fougere sync` writes classes
|
|
292
|
+
// because its source is ANOTHER repo, and here the author can just import.
|
|
293
|
+
const stated = ['fronds.ts', 'fronds.mts', 'fronds.js', 'fronds.mjs']
|
|
294
|
+
.map((f) => resolve(scanRoot, f)).find((f) => existsSync(f));
|
|
295
|
+
|
|
296
|
+
// No statement of its own: the build writes the one the scan implies, so the runtime
|
|
297
|
+
// never reaches `scanProject`. That fallback works — it has a disk under Nuxt — but it
|
|
298
|
+
// loads `typescript` into a production boot, which is the whole of what a build is for.
|
|
299
|
+
// What is written is the STATEMENT (imports + `frond()`), never the scan result.
|
|
300
|
+
// `.ts`, and it is not cosmetic: the file spells its imports the way TypeScript sources
|
|
301
|
+
// do (`Post.js` for `Post.ts`), and Nitro externalizes a `.mjs` it can hand to Node —
|
|
302
|
+
// which then resolves `@fronds/*` against a package that does not exist, since an alias
|
|
303
|
+
// is a bundler's. Measured both ways, in-process: `.mjs` answers 500, `.ts` answers.
|
|
304
|
+
const statedPath = stated ?? addTemplate({
|
|
305
|
+
filename: 'fougere-fronds.ts',
|
|
257
306
|
write: true,
|
|
258
|
-
getContents: (
|
|
259
|
-
|
|
260
|
-
});
|
|
307
|
+
getContents: () => emitStatement(scan),
|
|
308
|
+
}).dst;
|
|
261
309
|
|
|
262
310
|
// ── 6b. Boot plugin (virtual — lives in .nuxt/) ───
|
|
263
311
|
const allSeeds = orderSeeds(fronds);
|
|
264
312
|
const bootTpl = addTemplate({
|
|
265
313
|
filename: 'fougere-boot.ts',
|
|
266
314
|
write: true,
|
|
267
|
-
getContents: () => generateBootPlugin(config, allSeeds, runtimeResolve('server/utils/boot'),
|
|
315
|
+
getContents: () => generateBootPlugin(config, allSeeds, runtimeResolve('server/utils/boot'), extensionsOf(options), statedPath),
|
|
268
316
|
});
|
|
269
317
|
addServerPlugin(bootTpl.dst);
|
|
270
318
|
|
|
@@ -324,8 +372,10 @@ export function generateBootPlugin(
|
|
|
324
372
|
config: FougereConfig,
|
|
325
373
|
seeds: SeedEntry[],
|
|
326
374
|
fougereAppPath: string,
|
|
327
|
-
/**
|
|
328
|
-
|
|
375
|
+
/** What `fougere:` named, in mount order. Empty is the whole of "changed nothing". */
|
|
376
|
+
extensions: { key: string; options: unknown }[] = [],
|
|
377
|
+
/** The app's own `fronds.ts`, when it states what it hosts instead of being scanned. */
|
|
378
|
+
statedPath?: string,
|
|
329
379
|
): string {
|
|
330
380
|
const lines: string[] = [];
|
|
331
381
|
lines.push(`// Auto-generated by @fougere/nuxt — do not edit`);
|
|
@@ -334,7 +384,12 @@ export function generateBootPlugin(
|
|
|
334
384
|
lines.push(`import { configureFougere } from '${fougereAppPath}';`);
|
|
335
385
|
// A STATIC import, because that is the one thing a bundler needs spelled out — and the
|
|
336
386
|
// whole point is that nothing reads a directory once this file is built.
|
|
337
|
-
|
|
387
|
+
// The extension is DROPPED, and that is what decides who reads the file: an extensionless
|
|
388
|
+
// specifier cannot be resolved by Node, so the bundler resolves it — and only a bundler
|
|
389
|
+
// applies the `@fronds/*` aliases the statement's own imports are written with. Left in
|
|
390
|
+
// place, the path resolves natively, Node reads the frond's `.ts` and every call answers
|
|
391
|
+
// 500. Measured both ways on demos/nuxt-blog, in-process.
|
|
392
|
+
if (statedPath) lines.push(`import fronds from '${statedPath.replace(/\.(m?)[jt]sx?$/, '')}';`);
|
|
338
393
|
|
|
339
394
|
const db = config.db ?? 'sqlite';
|
|
340
395
|
const sources = (config as { sources?: unknown }).sources;
|
|
@@ -349,7 +404,10 @@ export function generateBootPlugin(
|
|
|
349
404
|
if (!declaresStorage(db as Parameters<typeof declaresStorage>[0])) {
|
|
350
405
|
lines.push(``);
|
|
351
406
|
lines.push(`export default defineNitroPlugin(() => {`);
|
|
352
|
-
|
|
407
|
+
// Always configure, even with nothing to host: `hostedBy` is where the absence is
|
|
408
|
+
// answered, by name and with both keys. Skipping the call boots a silent app instead.
|
|
409
|
+
const states = statedPath ? 'fronds, ' : '';
|
|
410
|
+
lines.push(` configureFougere({ ${states}config: ${JSON.stringify(carried(config))} });`);
|
|
353
411
|
lines.push(`});`);
|
|
354
412
|
return lines.join('\n') + '\n';
|
|
355
413
|
}
|
|
@@ -359,6 +417,12 @@ export function generateBootPlugin(
|
|
|
359
417
|
lines.push(`import { resolveStorage } from '@fougere/defaults';`);
|
|
360
418
|
// After the early return above: an app that declares no storage generates no imports.
|
|
361
419
|
lines.push(`import { migrating${seeds.length ? ', runSeeds' : ''} } from '@fougere/core';`);
|
|
420
|
+
// One import per key the project named. The key IS the export and the package suffix, so
|
|
421
|
+
// a missing package is a build error naming the package — not a boot that silently lacks
|
|
422
|
+
// the panel someone asked for.
|
|
423
|
+
for (const { key } of extensions) {
|
|
424
|
+
lines.push(`import { ${key} } from '@fougere/${key}';`);
|
|
425
|
+
}
|
|
362
426
|
lines.push(``);
|
|
363
427
|
|
|
364
428
|
// Seed imports
|
|
@@ -369,14 +433,14 @@ export function generateBootPlugin(
|
|
|
369
433
|
|
|
370
434
|
// Wrap all init in the plugin callback to avoid top-level native calls
|
|
371
435
|
lines.push(`export default defineNitroPlugin(async () => {`);
|
|
372
|
-
//
|
|
373
|
-
// from being stated. Measured on workerd — `resolveStorage` threw on a native driver,
|
|
436
|
+
// What it HOSTS first, and on its own line: it names no engine, so nothing below can stop
|
|
437
|
+
// it from being stated. Measured on workerd — `resolveStorage` threw on a native driver,
|
|
374
438
|
// Nitro swallowed the plugin whole, and the app came up with zero fronds and not a word.
|
|
375
|
-
// Two unrelated facts had been sharing one failure.
|
|
376
|
-
//
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
439
|
+
// Two unrelated facts had been sharing one failure. `remotes` rides along for the same
|
|
440
|
+
// reason: it is the whole of why a consumer that hosts nothing boots at all.
|
|
441
|
+
const states = statedPath ? 'fronds, ' : '';
|
|
442
|
+
lines.push(` configureFougere({ ${states}config: ${JSON.stringify(carried(config))} });`);
|
|
443
|
+
lines.push(``);
|
|
380
444
|
lines.push(` try {`);
|
|
381
445
|
// Pass `db` through unchanged — resolveStorage (@fougere/defaults → setupSqlite)
|
|
382
446
|
// is the one place that defaults an absent path, so both call sites (this
|
|
@@ -387,7 +451,7 @@ export function generateBootPlugin(
|
|
|
387
451
|
lines.push(` const storage = resolveStorage(${JSON.stringify(db)}${sourcesArg});`);
|
|
388
452
|
lines.push(``);
|
|
389
453
|
lines.push(` configureFougere({`);
|
|
390
|
-
if (
|
|
454
|
+
if (statedPath) lines.push(` fronds,`);
|
|
391
455
|
lines.push(` config: ${JSON.stringify(carried(config))},`);
|
|
392
456
|
lines.push(` db: storage.db,`);
|
|
393
457
|
lines.push(` ormFactory: storage.ormFactory,`);
|
|
@@ -415,6 +479,12 @@ export function generateBootPlugin(
|
|
|
415
479
|
lines.push(` ], (message) => console.log('[fougere:seed]' + message)) },`);
|
|
416
480
|
}
|
|
417
481
|
|
|
482
|
+
// After the framework's own members, never before: tables, then rows, then what the host
|
|
483
|
+
// adds. A key named 'seeds' would REPLACE core's, which is the delta rule of AppLifecycle.
|
|
484
|
+
for (const { key, options } of extensions) {
|
|
485
|
+
lines.push(` ${key}(${JSON.stringify(options ?? {})}),`);
|
|
486
|
+
}
|
|
487
|
+
|
|
418
488
|
lines.push(` ],`);
|
|
419
489
|
lines.push(` });`);
|
|
420
490
|
// A storage that could not be opened is REPORTED, never swallowed. Nitro takes a
|
|
@@ -63,7 +63,17 @@ export async function useQuery<T = Record<string, unknown>>(
|
|
|
63
63
|
const total = computed(() => pageOf(data.value).total);
|
|
64
64
|
const hasMore = computed(() => pageOf(data.value).hasMore);
|
|
65
65
|
|
|
66
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
data: data as Ref<T | null>,
|
|
68
|
+
items,
|
|
69
|
+
total,
|
|
70
|
+
hasMore,
|
|
71
|
+
loading: pending,
|
|
72
|
+
error,
|
|
73
|
+
// Nuxt does not export AsyncDataExecuteOptions, so the inferred signature cannot
|
|
74
|
+
// be named from outside; callers pass nothing.
|
|
75
|
+
refresh: refresh as () => Promise<void>,
|
|
76
|
+
};
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
export function useCommand<T = unknown>(entity: EntityClass, op: string) {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { defineEventHandler } from 'h3';
|
|
11
11
|
import { serveRpc, rpcParseError, useFougereApp } from '@fougere/app';
|
|
12
|
+
import { MAX_BODY_BYTES } from '@fougere/core';
|
|
12
13
|
|
|
13
14
|
type NodeReq = {
|
|
14
15
|
body?: unknown;
|
|
@@ -22,7 +23,6 @@ type WebReq = {
|
|
|
22
23
|
json?: () => Promise<unknown>;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
|
-
const MAX_BODY_BYTES = 1024 * 1024;
|
|
26
26
|
|
|
27
27
|
function payloadTooLarge(): Error & { statusCode: number; statusMessage: string } {
|
|
28
28
|
return Object.assign(new Error('Payload too large'), { statusCode: 413, statusMessage: 'Payload too large' });
|
package/src/shims.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Nuxt's virtual barrel has no file to resolve to; the shim says where its types are,
|
|
2
|
+
// never what they say. (`nitropack/runtime` is redirected by tsconfig paths instead:
|
|
3
|
+
// it DOES resolve, and an ambient declaration cannot override a resolution.)
|
|
4
|
+
declare module '#imports' {
|
|
5
|
+
// Nuxt's virtual barrel, resolved when the app builds.
|
|
6
|
+
export * from 'nuxt/app';
|
|
7
|
+
}
|