@holo-js/cli 0.1.3 → 0.1.5
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/bin/holo.mjs +192 -35
- package/dist/{broadcast-YZS4OFCM.mjs → broadcast-RT5KVZWP.mjs} +5 -5
- package/dist/{cache-V43YMG4K.mjs → cache-NHCCHT44.mjs} +5 -5
- package/dist/{cache-migrations-ZUOI2A7N.mjs → cache-migrations-R2RL2RVD.mjs} +15 -16
- package/dist/{chunk-EUIVXVJL.mjs → chunk-57SJ566R.mjs} +1 -1
- package/dist/chunk-5BLEC66P.mjs +284 -0
- package/dist/{chunk-JX2ZH6XY.mjs → chunk-5EU32E7X.mjs} +3 -3
- package/dist/{chunk-Q5F6C2D4.mjs → chunk-BAFQ2GOA.mjs} +1 -1
- package/dist/{chunk-CUL4RJTG.mjs → chunk-F4MT6GBK.mjs} +1 -1
- package/dist/{chunk-3OTCSFDG.mjs → chunk-MXKNQACM.mjs} +544 -82
- package/dist/{chunk-QYLSMF7V.mjs → chunk-OZUDZEAW.mjs} +142 -28
- package/dist/{chunk-66FHW725.mjs → chunk-R6BWRY3E.mjs} +28 -2
- package/dist/{chunk-RB65DLR4.mjs → chunk-SCCPDJGO.mjs} +156 -16
- package/dist/{chunk-VT5IDQG6.mjs → chunk-UZTDQKIY.mjs} +61 -44
- package/dist/{chunk-HE6FYNVN.mjs → chunk-VCEO6N5T.mjs} +3563 -2505
- package/dist/{config-LS5USBRB.mjs → config-5JSC6KJG.mjs} +3 -3
- package/dist/{dev-KGRIGLJY.mjs → dev-OSLYSBTL.mjs} +7 -7
- package/dist/{discovery-GBLAUTXS.mjs → discovery-JLT2EOGH.mjs} +3 -3
- package/dist/{generators-WSF23UKM.mjs → generators-ZIWACCBE.mjs} +134 -16
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +189 -32
- package/dist/media-migrations-UBAL2YVV.mjs +117 -0
- package/dist/{queue-6N7HQMRL.mjs → queue-I66EISVS.mjs} +14 -14
- package/dist/{queue-migrations-O6QSSDPQ.mjs → queue-migrations-UIAMAB6E.mjs} +24 -20
- package/dist/{runtime-RI4OWTIT.mjs → runtime-MMQGO4PP.mjs} +9 -7
- package/dist/{runtime-OOSJ5JBY.mjs → runtime-ZKD6URAV.mjs} +1 -1
- package/dist/{scaffold-IYWZKT3W.mjs → scaffold-ISDVICNQ.mjs} +18 -4
- package/dist/{security-AE6LGNC4.mjs → security-OZXTMYXF.mjs} +10 -7
- package/package.json +13 -12
- package/dist/broadcast-ZYFKUFM5.mjs +0 -85
- package/dist/cache-ODBZT6IP.mjs +0 -67
- package/dist/cache-migrations-KPOEH6GP.mjs +0 -155
- package/dist/chunk-BWW5TDFI.mjs +0 -4
- package/dist/chunk-D4GG556Y.mjs +0 -23
- package/dist/chunk-ET7UXHHQ.mjs +0 -166
- package/dist/chunk-G5ADO27Q.mjs +0 -463
- package/dist/chunk-GSQ3HTRO.mjs +0 -165
- package/dist/chunk-H7TJ4FB3.mjs +0 -848
- package/dist/chunk-ICJR7TS4.mjs +0 -66
- package/dist/chunk-ICKN56JY.mjs +0 -342
- package/dist/chunk-M7J3YTHR.mjs +0 -26
- package/dist/chunk-S7P7EBM3.mjs +0 -787
- package/dist/chunk-SRWJU3A5.mjs +0 -11
- package/dist/chunk-T4OVZZEE.mjs +0 -3204
- package/dist/chunk-URK7C3VQ.mjs +0 -538
- package/dist/chunk-XUYKPU5Q.mjs +0 -272
- package/dist/config-DMWBMMGD.mjs +0 -26
- package/dist/dev-LVHDCPVS.mjs +0 -43
- package/dist/discovery-R733D2PO.mjs +0 -29
- package/dist/generators-32R45P6Z.mjs +0 -426
- package/dist/queue-QG5EXOG4.mjs +0 -626
- package/dist/queue-migrations-JWKU45Y3.mjs +0 -163
- package/dist/runtime-ANBO7VQM.mjs +0 -33
- package/dist/runtime-ZRPK5DIT.mjs +0 -56
- package/dist/scaffold-ULATB4CA.mjs +0 -121
- package/dist/security-OCOPEH2V.mjs +0 -69
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
import {
|
|
3
2
|
CONFIG_EXTENSION_PRIORITY,
|
|
4
3
|
GENERATED_AUTHORIZATION_REGISTRY_PATH,
|
|
5
4
|
GENERATED_AUTHORIZATION_TYPES_PATH,
|
|
5
|
+
GENERATED_AUTH_TYPES_PATH,
|
|
6
6
|
GENERATED_BROADCAST_MANIFEST_PATH,
|
|
7
7
|
GENERATED_BROADCAST_PATH,
|
|
8
8
|
GENERATED_BROADCAST_TYPES_PATH,
|
|
@@ -18,20 +18,24 @@ import {
|
|
|
18
18
|
GENERATED_METADATA_PATH,
|
|
19
19
|
GENERATED_MIGRATIONS_PATH,
|
|
20
20
|
GENERATED_MODELS_PATH,
|
|
21
|
+
GENERATED_MODEL_TYPES_PATH,
|
|
21
22
|
GENERATED_QUEUE_TYPES_PATH,
|
|
22
23
|
GENERATED_REGISTRY_JSON_PATH,
|
|
23
24
|
GENERATED_ROOT,
|
|
25
|
+
GENERATED_SCHEMA_RUNTIME_PATH,
|
|
24
26
|
GENERATED_SEEDERS_PATH,
|
|
27
|
+
GENERATED_SVELTE_HOOKS_PATH,
|
|
28
|
+
GENERATED_SVELTE_SERVER_HOOKS_PATH,
|
|
25
29
|
GENERATED_TSCONFIG_PATH,
|
|
26
30
|
SUPPORTED_CONFIG_EXTENSIONS,
|
|
27
31
|
importProjectModule,
|
|
28
32
|
isRecord,
|
|
29
|
-
makeProjectRelativePath
|
|
30
|
-
|
|
31
|
-
} from "./chunk-66FHW725.mjs";
|
|
33
|
+
makeProjectRelativePath
|
|
34
|
+
} from "./chunk-R6BWRY3E.mjs";
|
|
32
35
|
|
|
33
36
|
// src/templates.ts
|
|
34
37
|
import { dirname, relative, resolve } from "path";
|
|
38
|
+
import inflection from "inflection";
|
|
35
39
|
function toPosixPath(value) {
|
|
36
40
|
return value.replace(/\\/g, "/");
|
|
37
41
|
}
|
|
@@ -63,13 +67,7 @@ function toKebabCase(value) {
|
|
|
63
67
|
return toSnakeCase(value).replaceAll("_", "-");
|
|
64
68
|
}
|
|
65
69
|
function pluralize(word) {
|
|
66
|
-
|
|
67
|
-
return `${word.slice(0, -1)}ies`;
|
|
68
|
-
}
|
|
69
|
-
if (/(?:[sxz]|ch|sh)$/i.test(word)) {
|
|
70
|
-
return `${word}es`;
|
|
71
|
-
}
|
|
72
|
-
return `${word}s`;
|
|
70
|
+
return inflection.pluralize(word);
|
|
73
71
|
}
|
|
74
72
|
function ensureSuffix(name, suffix) {
|
|
75
73
|
return name.endsWith(suffix) ? name : `${name}${suffix}`;
|
|
@@ -80,28 +78,17 @@ function relativeImportPath(fromFile, toFile) {
|
|
|
80
78
|
return target.startsWith(".") ? target : `./${target}`;
|
|
81
79
|
}
|
|
82
80
|
function renderModelTemplate(options) {
|
|
83
|
-
const imports = [
|
|
84
|
-
`import { tables as holoGeneratedTables } from '${options.generatedSchemaImportPath}'`,
|
|
85
|
-
"import { defineModel, type TableDefinition } from '@holo-js/db'"
|
|
86
|
-
];
|
|
81
|
+
const imports = ["import { defineModel } from '@holo-js/db'"];
|
|
87
82
|
if (options.observerImportPath && options.observerClassName) {
|
|
88
83
|
imports.push(`import { ${options.observerClassName} } from '${options.observerImportPath}'`);
|
|
89
84
|
}
|
|
90
85
|
return [
|
|
91
86
|
...imports,
|
|
92
87
|
"",
|
|
93
|
-
`
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
"
|
|
97
|
-
" ? undefined",
|
|
98
|
-
" : defineModel(",
|
|
99
|
-
" holoModelTable,",
|
|
100
|
-
" {",
|
|
101
|
-
" fillable: [],",
|
|
102
|
-
...options.observerClassName ? [` observers: [${options.observerClassName}],`] : [],
|
|
103
|
-
" },",
|
|
104
|
-
" )",
|
|
88
|
+
`export default defineModel(${JSON.stringify(options.tableName)}, {`,
|
|
89
|
+
" fillable: [],",
|
|
90
|
+
...options.observerClassName ? [` observers: [${options.observerClassName}],`] : [],
|
|
91
|
+
"})",
|
|
105
92
|
""
|
|
106
93
|
].join("\n");
|
|
107
94
|
}
|
|
@@ -267,10 +254,336 @@ function resolveArtifactPath(root, subdir, directory, fileName) {
|
|
|
267
254
|
}
|
|
268
255
|
|
|
269
256
|
// src/project/registry.ts
|
|
270
|
-
import {
|
|
271
|
-
import {
|
|
257
|
+
import { constants as fsConstants } from "fs";
|
|
258
|
+
import { access, mkdir as mkdir2, readFile as readFile2, readdir, writeFile as writeFile2 } from "fs/promises";
|
|
259
|
+
import { dirname as dirname3, extname, join, resolve as resolve3 } from "path";
|
|
272
260
|
import { loadConfigDirectory } from "@holo-js/config";
|
|
273
|
-
import { DEFAULT_HOLO_PROJECT_PATHS } from "@holo-js/db";
|
|
261
|
+
import { DEFAULT_HOLO_PROJECT_PATHS, renderGeneratedSchemaRuntimeModule } from "@holo-js/db";
|
|
262
|
+
|
|
263
|
+
// src/project/registry-svelte.ts
|
|
264
|
+
import { mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
265
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
266
|
+
function renderManagedSvelteHooksModule() {
|
|
267
|
+
return [
|
|
268
|
+
"// Generated by holo prepare. Do not edit.",
|
|
269
|
+
"",
|
|
270
|
+
"import type { Reroute } from '@sveltejs/kit'",
|
|
271
|
+
"import { holoSvelteKitTransport } from '@holo-js/adapter-sveltekit/transport'",
|
|
272
|
+
"import * as userHooks from '../../src/hooks'",
|
|
273
|
+
"",
|
|
274
|
+
"const universalHooks = userHooks as {",
|
|
275
|
+
" reroute?: Reroute",
|
|
276
|
+
" transport?: Partial<typeof holoSvelteKitTransport>",
|
|
277
|
+
"}",
|
|
278
|
+
"",
|
|
279
|
+
"function normalizeStorageRoutePrefix(value: string | undefined): string {",
|
|
280
|
+
" const raw = value?.trim() ?? '/storage'",
|
|
281
|
+
" if (!raw || raw === '/') {",
|
|
282
|
+
" return '/storage'",
|
|
283
|
+
" }",
|
|
284
|
+
"",
|
|
285
|
+
" return `/${raw.replace(/^\\/+|\\/+$/g, '')}`",
|
|
286
|
+
"}",
|
|
287
|
+
"",
|
|
288
|
+
"function resolveStorageRoutePrefix(): string {",
|
|
289
|
+
" return normalizeStorageRoutePrefix(typeof process === 'undefined' ? undefined : process.env.STORAGE_ROUTE_PREFIX)",
|
|
290
|
+
"}",
|
|
291
|
+
"",
|
|
292
|
+
"export const reroute: Reroute = async (event) => {",
|
|
293
|
+
" const userPath = await universalHooks.reroute?.(event)",
|
|
294
|
+
" const pathname = typeof userPath === 'string' ? userPath : event.url.pathname",
|
|
295
|
+
" const storageRoutePrefix = resolveStorageRoutePrefix()",
|
|
296
|
+
"",
|
|
297
|
+
" if (storageRoutePrefix !== '/storage' && (pathname === storageRoutePrefix || pathname.startsWith(`${storageRoutePrefix}/`))) {",
|
|
298
|
+
" const suffix = pathname.slice(storageRoutePrefix.length)",
|
|
299
|
+
" return suffix ? `/storage${suffix}` : '/storage'",
|
|
300
|
+
" }",
|
|
301
|
+
"",
|
|
302
|
+
" return userPath",
|
|
303
|
+
"}",
|
|
304
|
+
"export const transport = {",
|
|
305
|
+
" ...(universalHooks.transport ?? {}),",
|
|
306
|
+
" ...holoSvelteKitTransport,",
|
|
307
|
+
"}",
|
|
308
|
+
""
|
|
309
|
+
].join("\n");
|
|
310
|
+
}
|
|
311
|
+
function renderManagedSvelteServerHooksModule() {
|
|
312
|
+
return [
|
|
313
|
+
"// Generated by holo prepare. Do not edit.",
|
|
314
|
+
"",
|
|
315
|
+
"import { error as svelteKitError, type Handle, type HandleFetch, type HandleServerError } from '@sveltejs/kit'",
|
|
316
|
+
"import { adapterSvelteKitInternals, runWithSvelteKitRequestEvent } from '@holo-js/adapter-sveltekit'",
|
|
317
|
+
"import { sequence } from '@sveltejs/kit/hooks'",
|
|
318
|
+
"import { holo } from '$lib/server/holo'",
|
|
319
|
+
"import * as userHooks from '../../src/hooks.server'",
|
|
320
|
+
"",
|
|
321
|
+
"const serverHooks = userHooks as {",
|
|
322
|
+
" handle?: Handle",
|
|
323
|
+
" handleError?: HandleServerError",
|
|
324
|
+
" handleFetch?: HandleFetch",
|
|
325
|
+
"}",
|
|
326
|
+
"",
|
|
327
|
+
"function isHoloAuthorizationHttpError(cause: unknown): cause is Error & { readonly decision: { readonly status: 403 | 404 } } {",
|
|
328
|
+
" if (!(cause instanceof Error) || cause.name !== 'AuthorizationError') {",
|
|
329
|
+
" return false",
|
|
330
|
+
" }",
|
|
331
|
+
"",
|
|
332
|
+
" const decision = (cause as { readonly decision?: { readonly status?: unknown } }).decision",
|
|
333
|
+
" return decision?.status === 403 || decision?.status === 404",
|
|
334
|
+
"}",
|
|
335
|
+
"",
|
|
336
|
+
"function serializeHoloValidationException(cause: unknown) {",
|
|
337
|
+
" return adapterSvelteKitInternals.serializeValidationException(cause) ?? null",
|
|
338
|
+
"}",
|
|
339
|
+
"",
|
|
340
|
+
"const holoHandle: Handle = ({ event, resolve }) => runWithSvelteKitRequestEvent(event, async () => {",
|
|
341
|
+
" await holo.getApp()",
|
|
342
|
+
"",
|
|
343
|
+
" try {",
|
|
344
|
+
" const response = await resolve(event)",
|
|
345
|
+
" return await adapterSvelteKitInternals.mapValidationActionResponse(event, response)",
|
|
346
|
+
" } catch (cause) {",
|
|
347
|
+
" if (isHoloAuthorizationHttpError(cause)) {",
|
|
348
|
+
" svelteKitError(cause.decision.status, cause.message)",
|
|
349
|
+
" }",
|
|
350
|
+
"",
|
|
351
|
+
" const validationPayload = serializeHoloValidationException(cause)",
|
|
352
|
+
" if (validationPayload) {",
|
|
353
|
+
" if (adapterSvelteKitInternals.isApiEvent(event)) {",
|
|
354
|
+
" return Response.json(validationPayload, { status: validationPayload.status })",
|
|
355
|
+
" }",
|
|
356
|
+
"",
|
|
357
|
+
" throw cause",
|
|
358
|
+
" }",
|
|
359
|
+
"",
|
|
360
|
+
" throw cause",
|
|
361
|
+
" }",
|
|
362
|
+
"})",
|
|
363
|
+
"",
|
|
364
|
+
"const holoHandleError: HandleServerError = async (input) => {",
|
|
365
|
+
" const validationPayload = serializeHoloValidationException(input.error)",
|
|
366
|
+
" if (validationPayload) {",
|
|
367
|
+
" adapterSvelteKitInternals.rememberValidationActionFailure(input.event, validationPayload)",
|
|
368
|
+
" return validationPayload",
|
|
369
|
+
" }",
|
|
370
|
+
"",
|
|
371
|
+
" if (serverHooks.handleError) {",
|
|
372
|
+
" return await serverHooks.handleError(input)",
|
|
373
|
+
" }",
|
|
374
|
+
"",
|
|
375
|
+
" return {",
|
|
376
|
+
" message: input.error instanceof Error ? input.error.message : 'Internal server error',",
|
|
377
|
+
" }",
|
|
378
|
+
"}",
|
|
379
|
+
"",
|
|
380
|
+
"export const handle = typeof serverHooks.handle === 'function'",
|
|
381
|
+
" ? sequence(holoHandle, serverHooks.handle)",
|
|
382
|
+
" : holoHandle",
|
|
383
|
+
"export const handleError = holoHandleError",
|
|
384
|
+
"export const handleFetch = serverHooks.handleFetch",
|
|
385
|
+
""
|
|
386
|
+
].join("\n");
|
|
387
|
+
}
|
|
388
|
+
function renderSvelteDefaultHooksModule() {
|
|
389
|
+
return [
|
|
390
|
+
"export {}",
|
|
391
|
+
""
|
|
392
|
+
].join("\n");
|
|
393
|
+
}
|
|
394
|
+
function renderSvelteDefaultServerHooksModule() {
|
|
395
|
+
return [
|
|
396
|
+
"export {}",
|
|
397
|
+
""
|
|
398
|
+
].join("\n");
|
|
399
|
+
}
|
|
400
|
+
function isManagedPrepareArtifact(contents) {
|
|
401
|
+
return contents.startsWith("// Generated by holo prepare. Do not edit.");
|
|
402
|
+
}
|
|
403
|
+
function isLegacySvelteTransportHook(contents) {
|
|
404
|
+
return contents.trim() === [
|
|
405
|
+
"import { holoSvelteKitTransport } from '@holo-js/adapter-sveltekit/transport'",
|
|
406
|
+
"",
|
|
407
|
+
"export const transport = holoSvelteKitTransport"
|
|
408
|
+
].join("\n").trim();
|
|
409
|
+
}
|
|
410
|
+
function isLegacySvelteServerHook(contents) {
|
|
411
|
+
return contents.trim() === [
|
|
412
|
+
"import '@holo-js/adapter-sveltekit'",
|
|
413
|
+
"",
|
|
414
|
+
"import type { Handle } from '@sveltejs/kit'",
|
|
415
|
+
"import { holo } from '$lib/server/holo'",
|
|
416
|
+
"",
|
|
417
|
+
"function normalizeStorageRoutePrefix(value: string | undefined): string {",
|
|
418
|
+
" const raw = value?.trim() ?? '/storage'",
|
|
419
|
+
" if (!raw || raw === '/') {",
|
|
420
|
+
" return '/storage'",
|
|
421
|
+
" }",
|
|
422
|
+
"",
|
|
423
|
+
" return `/${raw.replace(/^\\/+|\\/+$/g, '')}`",
|
|
424
|
+
"}",
|
|
425
|
+
"",
|
|
426
|
+
"export const handle: Handle = async ({ event, resolve }) => {",
|
|
427
|
+
" await holo.getApp()",
|
|
428
|
+
"",
|
|
429
|
+
" const storageRoutePrefix = normalizeStorageRoutePrefix(process.env.STORAGE_ROUTE_PREFIX)",
|
|
430
|
+
"",
|
|
431
|
+
" if (storageRoutePrefix !== '/storage') {",
|
|
432
|
+
" const pathname = event.url.pathname",
|
|
433
|
+
" if (pathname === storageRoutePrefix || pathname.startsWith(`${storageRoutePrefix}/`)) {",
|
|
434
|
+
" const suffix = pathname.slice(storageRoutePrefix.length)",
|
|
435
|
+
" event.url.pathname = suffix ? `/storage${suffix}` : '/storage'",
|
|
436
|
+
" }",
|
|
437
|
+
" }",
|
|
438
|
+
"",
|
|
439
|
+
" return resolve(event)",
|
|
440
|
+
"}"
|
|
441
|
+
].join("\n").trim();
|
|
442
|
+
}
|
|
443
|
+
async function readFileIfPresent(path) {
|
|
444
|
+
try {
|
|
445
|
+
return await readFile(path, "utf8");
|
|
446
|
+
} catch {
|
|
447
|
+
return void 0;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async function unlinkIfPresent(path) {
|
|
451
|
+
try {
|
|
452
|
+
await unlink(path);
|
|
453
|
+
} catch {
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
var SVELTE_HOOKS_OVERRIDE_BLOCK = [
|
|
457
|
+
" files: {",
|
|
458
|
+
" hooks: {",
|
|
459
|
+
" server: '.holo-js/generated/hooks.server',",
|
|
460
|
+
" universal: '.holo-js/generated/hooks',",
|
|
461
|
+
" },",
|
|
462
|
+
" },"
|
|
463
|
+
].join("\n");
|
|
464
|
+
var SVELTE_CONFIG_WRAPPER_IMPORT = "import { withHoloSvelteKit } from '@holo-js/adapter-sveltekit/config'";
|
|
465
|
+
var LEGACY_SVELTE_PREPROCESS_IMPORT = "import { holoSveltePreprocess } from '@holo-js/adapter-sveltekit'";
|
|
466
|
+
var LEGACY_SVELTE_PREPROCESS_CALL = "holoSveltePreprocess()";
|
|
467
|
+
var SVELTE_CONFIG_WRAPPER_CALL = "withHoloSvelteKit(";
|
|
468
|
+
function getSvelteConfigHooksOverrideState(contents) {
|
|
469
|
+
if (contents.includes(".holo-js/generated/hooks")) {
|
|
470
|
+
return "managed";
|
|
471
|
+
}
|
|
472
|
+
if (/kit\s*:\s*\{[\s\S]*?files\s*:\s*\{[\s\S]*?hooks\s*:/.test(contents)) {
|
|
473
|
+
return "custom";
|
|
474
|
+
}
|
|
475
|
+
return "none";
|
|
476
|
+
}
|
|
477
|
+
function assertSvelteConfigHasNoCustomHookOverride(contents) {
|
|
478
|
+
const hooksOverrideState = getSvelteConfigHooksOverrideState(contents);
|
|
479
|
+
if (hooksOverrideState === "custom") {
|
|
480
|
+
throw new Error("Custom SvelteKit hook entrypoints are not supported. Remove kit.files.hooks from svelte.config.js and let holo prepare manage the generated hook bridge.");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
function ensureSvelteConfigWrapperImport(contents) {
|
|
484
|
+
if (contents.includes(SVELTE_CONFIG_WRAPPER_IMPORT)) {
|
|
485
|
+
return contents;
|
|
486
|
+
}
|
|
487
|
+
const lastImport = [...contents.matchAll(/^import .+$/gm)].at(-1);
|
|
488
|
+
if (!lastImport || lastImport.index === void 0) {
|
|
489
|
+
return `${SVELTE_CONFIG_WRAPPER_IMPORT}
|
|
490
|
+
${contents}`;
|
|
491
|
+
}
|
|
492
|
+
const insertAt = lastImport.index + lastImport[0].length;
|
|
493
|
+
return `${contents.slice(0, insertAt)}
|
|
494
|
+
${SVELTE_CONFIG_WRAPPER_IMPORT}${contents.slice(insertAt)}`;
|
|
495
|
+
}
|
|
496
|
+
function removeLegacySvelteConfigWiring(contents) {
|
|
497
|
+
return contents.replace(`${LEGACY_SVELTE_PREPROCESS_IMPORT}
|
|
498
|
+
`, "").replace(new RegExp(String.raw`,\s*${LEGACY_SVELTE_PREPROCESS_CALL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "g"), "").replace(new RegExp(String.raw`${LEGACY_SVELTE_PREPROCESS_CALL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\s*,\s*`, "g"), "").replace(`${SVELTE_HOOKS_OVERRIDE_BLOCK}
|
|
499
|
+
`, "");
|
|
500
|
+
}
|
|
501
|
+
function patchSvelteConfigWithHoloWrapper(contents) {
|
|
502
|
+
assertSvelteConfigHasNoCustomHookOverride(contents);
|
|
503
|
+
const cleaned = ensureSvelteConfigWrapperImport(removeLegacySvelteConfigWiring(contents));
|
|
504
|
+
if (cleaned.includes(SVELTE_CONFIG_WRAPPER_CALL)) {
|
|
505
|
+
return cleaned === contents ? void 0 : cleaned;
|
|
506
|
+
}
|
|
507
|
+
const constConfigPattern = /(const\s+config\s*=\s*)\{/;
|
|
508
|
+
if (!constConfigPattern.test(cleaned)) {
|
|
509
|
+
throw new Error("Could not patch svelte.config.js with withHoloSvelteKit(). Export a const config object so holo prepare can manage the SvelteKit integration.");
|
|
510
|
+
}
|
|
511
|
+
const wrappedOpening = cleaned.replace(constConfigPattern, `$1${SVELTE_CONFIG_WRAPPER_CALL}{`);
|
|
512
|
+
const wrapped = wrappedOpening.replace(/\}\s*export\s+default\s+config\s*$/u, "})\n\nexport default config");
|
|
513
|
+
if (wrapped === wrappedOpening) {
|
|
514
|
+
throw new Error("Could not patch svelte.config.js with withHoloSvelteKit(). Export a const config object so holo prepare can manage the SvelteKit integration.");
|
|
515
|
+
}
|
|
516
|
+
return wrapped;
|
|
517
|
+
}
|
|
518
|
+
async function ensureSvelteConfigHooksOverride(projectRoot) {
|
|
519
|
+
const configPath = resolve2(projectRoot, "svelte.config.js");
|
|
520
|
+
const contents = await readFileIfPresent(configPath);
|
|
521
|
+
if (!contents) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const patched = patchSvelteConfigWithHoloWrapper(contents) ?? contents;
|
|
525
|
+
if (patched !== contents) {
|
|
526
|
+
await writeFile(configPath, patched, "utf8");
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
async function writeFileIfChanged(path, contents) {
|
|
530
|
+
if (await readFileIfPresent(path) === contents) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
await mkdir(dirname2(path), { recursive: true });
|
|
534
|
+
await writeFile(path, contents, "utf8");
|
|
535
|
+
}
|
|
536
|
+
async function ensureSvelteManagedHooks(projectRoot) {
|
|
537
|
+
const hooksPath = resolve2(projectRoot, "src/hooks.ts");
|
|
538
|
+
const hooksServerPath = resolve2(projectRoot, "src/hooks.server.ts");
|
|
539
|
+
const generatedHooksPath = resolve2(projectRoot, GENERATED_SVELTE_HOOKS_PATH);
|
|
540
|
+
const generatedServerHooksPath = resolve2(projectRoot, GENERATED_SVELTE_SERVER_HOOKS_PATH);
|
|
541
|
+
const legacyHooksUserPath = resolve2(projectRoot, "src/hooks.user.ts");
|
|
542
|
+
const legacyHooksServerUserPath = resolve2(projectRoot, "src/hooks.server.user.ts");
|
|
543
|
+
const [hooksContents, hooksServerContents, legacyUserContents, legacyServerUserContents] = await Promise.all([
|
|
544
|
+
readFileIfPresent(hooksPath),
|
|
545
|
+
readFileIfPresent(hooksServerPath),
|
|
546
|
+
readFileIfPresent(legacyHooksUserPath),
|
|
547
|
+
readFileIfPresent(legacyHooksServerUserPath)
|
|
548
|
+
]);
|
|
549
|
+
if (legacyUserContents && (!hooksContents || isManagedPrepareArtifact(hooksContents))) {
|
|
550
|
+
await writeFileIfChanged(hooksPath, legacyUserContents);
|
|
551
|
+
await unlinkIfPresent(legacyHooksUserPath);
|
|
552
|
+
} else if (legacyUserContents && hooksContents === legacyUserContents) {
|
|
553
|
+
await unlinkIfPresent(legacyHooksUserPath);
|
|
554
|
+
}
|
|
555
|
+
if (legacyServerUserContents && (!hooksServerContents || isManagedPrepareArtifact(hooksServerContents))) {
|
|
556
|
+
await writeFileIfChanged(hooksServerPath, legacyServerUserContents);
|
|
557
|
+
await unlinkIfPresent(legacyHooksServerUserPath);
|
|
558
|
+
} else if (legacyServerUserContents && hooksServerContents === legacyServerUserContents) {
|
|
559
|
+
await unlinkIfPresent(legacyHooksServerUserPath);
|
|
560
|
+
}
|
|
561
|
+
const currentHooks = await readFileIfPresent(hooksPath);
|
|
562
|
+
if (!currentHooks || isManagedPrepareArtifact(currentHooks) || isLegacySvelteTransportHook(currentHooks)) {
|
|
563
|
+
await writeFileIfChanged(hooksPath, renderSvelteDefaultHooksModule());
|
|
564
|
+
}
|
|
565
|
+
const currentServerHooks = await readFileIfPresent(hooksServerPath);
|
|
566
|
+
if (!currentServerHooks || isManagedPrepareArtifact(currentServerHooks) || isLegacySvelteServerHook(currentServerHooks)) {
|
|
567
|
+
await writeFileIfChanged(hooksServerPath, renderSvelteDefaultServerHooksModule());
|
|
568
|
+
}
|
|
569
|
+
await writeFileIfChanged(generatedHooksPath, renderManagedSvelteHooksModule());
|
|
570
|
+
await writeFileIfChanged(generatedServerHooksPath, renderManagedSvelteServerHooksModule());
|
|
571
|
+
await ensureSvelteConfigHooksOverride(projectRoot);
|
|
572
|
+
}
|
|
573
|
+
async function syncManagedFrameworkArtifacts(projectRoot) {
|
|
574
|
+
let manifest;
|
|
575
|
+
try {
|
|
576
|
+
const content = await readFile(resolve2(projectRoot, ".holo-js/framework/project.json"), "utf8");
|
|
577
|
+
manifest = JSON.parse(content);
|
|
578
|
+
} catch {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (manifest.framework === "sveltekit") {
|
|
582
|
+
await ensureSvelteManagedHooks(projectRoot);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/project/registry.ts
|
|
274
587
|
function renderGeneratedModule(exportName, value) {
|
|
275
588
|
return [
|
|
276
589
|
"// Generated by holo prepare. Do not edit.",
|
|
@@ -281,6 +594,39 @@ function renderGeneratedModule(exportName, value) {
|
|
|
281
594
|
""
|
|
282
595
|
].join("\n");
|
|
283
596
|
}
|
|
597
|
+
function isGeneratedSchemaTable(value) {
|
|
598
|
+
return isRecord(value) && value.kind === "table" && typeof value.tableName === "string" && isRecord(value.columns);
|
|
599
|
+
}
|
|
600
|
+
function extractGeneratedSchemaTables(moduleValue) {
|
|
601
|
+
if (isRecord(moduleValue) && isRecord(moduleValue.tables)) {
|
|
602
|
+
return Object.values(moduleValue.tables).filter(isGeneratedSchemaTable);
|
|
603
|
+
}
|
|
604
|
+
if (isRecord(moduleValue) && isGeneratedSchemaTable(moduleValue.default)) {
|
|
605
|
+
return [moduleValue.default];
|
|
606
|
+
}
|
|
607
|
+
if (isRecord(moduleValue)) {
|
|
608
|
+
return Object.values(moduleValue).filter(isGeneratedSchemaTable);
|
|
609
|
+
}
|
|
610
|
+
return [];
|
|
611
|
+
}
|
|
612
|
+
function getFilesystemErrorCode(error) {
|
|
613
|
+
return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
614
|
+
}
|
|
615
|
+
async function renderGeneratedSchemaRuntimeArtifact(projectRoot, schemaEntry) {
|
|
616
|
+
const schemaPath = resolve3(projectRoot, schemaEntry);
|
|
617
|
+
try {
|
|
618
|
+
await access(schemaPath, fsConstants.R_OK);
|
|
619
|
+
} catch (error) {
|
|
620
|
+
const code = getFilesystemErrorCode(error);
|
|
621
|
+
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
622
|
+
return renderGeneratedSchemaRuntimeModule([]);
|
|
623
|
+
}
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
const moduleValue = await importProjectModule(projectRoot, schemaPath);
|
|
627
|
+
const tables = extractGeneratedSchemaTables(moduleValue);
|
|
628
|
+
return renderGeneratedSchemaRuntimeModule(tables);
|
|
629
|
+
}
|
|
284
630
|
function renderGeneratedIndexModule() {
|
|
285
631
|
return [
|
|
286
632
|
"// Generated by holo prepare. Do not edit.",
|
|
@@ -288,9 +634,11 @@ function renderGeneratedIndexModule() {
|
|
|
288
634
|
"/* eslint-disable @typescript-eslint/triple-slash-reference */",
|
|
289
635
|
"",
|
|
290
636
|
'/// <reference path="./broadcast.d.ts" />',
|
|
637
|
+
'/// <reference path="./auth.d.ts" />',
|
|
291
638
|
'/// <reference path="./authorization/types.d.ts" />',
|
|
292
639
|
'/// <reference path="./config.d.ts" />',
|
|
293
640
|
'/// <reference path="./events.d.ts" />',
|
|
641
|
+
'/// <reference path="./model-registry.d.ts" />',
|
|
294
642
|
'/// <reference path="./queue.d.ts" />',
|
|
295
643
|
"",
|
|
296
644
|
"import metadata from './metadata'",
|
|
@@ -328,6 +676,40 @@ function renderGeneratedIndexModule() {
|
|
|
328
676
|
""
|
|
329
677
|
].join("\n");
|
|
330
678
|
}
|
|
679
|
+
function renderGeneratedModelTypes(models) {
|
|
680
|
+
const aliases = models.map((entry, index) => {
|
|
681
|
+
return `type HoloModel${index} = ModelReference<GeneratedSchemaTable<${JSON.stringify(entry.tableName)}>, EmptyScopeMap>`;
|
|
682
|
+
});
|
|
683
|
+
const modelTypeImports = aliases.length > 0 ? [
|
|
684
|
+
"import type { EmptyScopeMap, GeneratedSchemaTable, ModelReference } from '@holo-js/db'",
|
|
685
|
+
""
|
|
686
|
+
] : [];
|
|
687
|
+
const registryEntries = models.map((entry, index) => {
|
|
688
|
+
return ` readonly ${JSON.stringify(entry.name)}: HoloModel${index}`;
|
|
689
|
+
});
|
|
690
|
+
const registeredModelsDeclaration = registryEntries.length > 0 ? [
|
|
691
|
+
" interface RegisteredModels {",
|
|
692
|
+
...registryEntries,
|
|
693
|
+
" }"
|
|
694
|
+
] : [
|
|
695
|
+
" // eslint-disable-next-line @typescript-eslint/no-empty-object-type",
|
|
696
|
+
" interface RegisteredModels {}"
|
|
697
|
+
];
|
|
698
|
+
return [
|
|
699
|
+
"// Generated by holo prepare. Do not edit.",
|
|
700
|
+
"",
|
|
701
|
+
"import './schema.generated'",
|
|
702
|
+
...modelTypeImports,
|
|
703
|
+
...aliases,
|
|
704
|
+
"",
|
|
705
|
+
"declare module '@holo-js/db' {",
|
|
706
|
+
...registeredModelsDeclaration,
|
|
707
|
+
"}",
|
|
708
|
+
"",
|
|
709
|
+
"export {}",
|
|
710
|
+
""
|
|
711
|
+
].join("\n");
|
|
712
|
+
}
|
|
331
713
|
function renderAugmentationInterface(name, members) {
|
|
332
714
|
if (members.length === 0) {
|
|
333
715
|
return [
|
|
@@ -398,7 +780,9 @@ function renderGeneratedBroadcastTypes(broadcast, channels) {
|
|
|
398
780
|
}
|
|
399
781
|
function renderGeneratedBroadcastManifest(registry) {
|
|
400
782
|
const hasPresenceChannels = registry.channels.some((entry) => entry.type === "presence");
|
|
401
|
-
const manifestImports = hasPresenceChannels ? [
|
|
783
|
+
const manifestImports = hasPresenceChannels ? [
|
|
784
|
+
"import type { ChannelPresenceMemberFor } from '@holo-js/broadcast'"
|
|
785
|
+
] : [];
|
|
402
786
|
const eventLines = registry.broadcast.flatMap((entry, index) => {
|
|
403
787
|
const lines = [
|
|
404
788
|
" {",
|
|
@@ -436,6 +820,30 @@ function renderGeneratedBroadcastManifest(registry) {
|
|
|
436
820
|
"// Generated by holo prepare. Do not edit.",
|
|
437
821
|
"",
|
|
438
822
|
...manifestImports,
|
|
823
|
+
...manifestImports.length > 0 ? [""] : [],
|
|
824
|
+
"type GeneratedBroadcastManifestEvent = {",
|
|
825
|
+
" readonly name: string",
|
|
826
|
+
" readonly channels: readonly {",
|
|
827
|
+
" readonly type: 'public' | 'private' | 'presence'",
|
|
828
|
+
" readonly pattern: string",
|
|
829
|
+
" }[]",
|
|
830
|
+
"}",
|
|
831
|
+
"",
|
|
832
|
+
"type GeneratedBroadcastManifestChannel = {",
|
|
833
|
+
" readonly name: string",
|
|
834
|
+
" readonly pattern: string",
|
|
835
|
+
" readonly type: 'private' | 'presence'",
|
|
836
|
+
" readonly params: readonly string[]",
|
|
837
|
+
" readonly whispers: readonly string[]",
|
|
838
|
+
" readonly member?: Readonly<Record<string, unknown>>",
|
|
839
|
+
"}",
|
|
840
|
+
"",
|
|
841
|
+
"type GeneratedBroadcastManifest = {",
|
|
842
|
+
" readonly version: 1",
|
|
843
|
+
" readonly generatedAt: string",
|
|
844
|
+
" readonly events: readonly GeneratedBroadcastManifestEvent[]",
|
|
845
|
+
" readonly channels: readonly GeneratedBroadcastManifestChannel[]",
|
|
846
|
+
"}",
|
|
439
847
|
"",
|
|
440
848
|
"export const broadcastManifest = {",
|
|
441
849
|
" version: 1,",
|
|
@@ -543,6 +951,37 @@ function renderGeneratedQueueTypes(jobs) {
|
|
|
543
951
|
""
|
|
544
952
|
].join("\n");
|
|
545
953
|
}
|
|
954
|
+
function renderGeneratedAuthTypes(guards) {
|
|
955
|
+
const members = Object.entries(guards).sort(([left], [right]) => left.localeCompare(right)).filter((entry) => {
|
|
956
|
+
return entry[1].driver === "session" || entry[1].driver === "token";
|
|
957
|
+
}).map(([name, guard]) => {
|
|
958
|
+
return ` readonly ${JSON.stringify(name)}: ${JSON.stringify(guard.driver)}`;
|
|
959
|
+
});
|
|
960
|
+
const guardsMember = members.length > 0 ? [
|
|
961
|
+
" guards: {",
|
|
962
|
+
...members,
|
|
963
|
+
" }"
|
|
964
|
+
] : [
|
|
965
|
+
" guards: Readonly<Record<string, 'session'>>"
|
|
966
|
+
];
|
|
967
|
+
return [
|
|
968
|
+
"// Generated by holo prepare. Do not edit.",
|
|
969
|
+
"",
|
|
970
|
+
"import '@holo-js/auth'",
|
|
971
|
+
"",
|
|
972
|
+
"declare global {",
|
|
973
|
+
" // eslint-disable-next-line @typescript-eslint/no-namespace",
|
|
974
|
+
" namespace HoloAuth {",
|
|
975
|
+
" interface TypeRegistry {",
|
|
976
|
+
...guardsMember,
|
|
977
|
+
" }",
|
|
978
|
+
" }",
|
|
979
|
+
"}",
|
|
980
|
+
"",
|
|
981
|
+
"export {}",
|
|
982
|
+
""
|
|
983
|
+
].join("\n");
|
|
984
|
+
}
|
|
546
985
|
function renderGeneratedAuthorizationRegistry(registry) {
|
|
547
986
|
return [
|
|
548
987
|
"// Generated by holo prepare. Do not edit.",
|
|
@@ -585,7 +1024,11 @@ function renderGeneratedAuthorizationTypes(authorizationPolicies, authorizationA
|
|
|
585
1024
|
const typedAbilityEntries = authorizationAbilities.filter((entry) => [".ts", ".mts", ".cts"].includes(extname(entry.sourcePath)));
|
|
586
1025
|
const policyImportNameByName = new Map(typedPolicyEntries.map((entry, index) => [entry.name, `holoAuthorizationPolicyModule${index}`]));
|
|
587
1026
|
const abilityImportNameByName = new Map(typedAbilityEntries.map((entry, index) => [entry.name, `holoAuthorizationAbilityModule${index}`]));
|
|
1027
|
+
const usesHoloAuthUser = authorizationPolicies.length > 0 || authorizationAbilities.length > 0 || guardNames.length > 0;
|
|
588
1028
|
const imports = [
|
|
1029
|
+
...typedPolicyEntries.length > 0 ? ["import type { AuthorizationPolicyDefinition as HoloAuthorizationPolicyDefinition } from '@holo-js/authorization/contracts'"] : [],
|
|
1030
|
+
...typedAbilityEntries.length > 0 ? ["import type { AuthorizationAbilityDefinition as HoloAuthorizationAbilityDefinition } from '@holo-js/authorization/contracts'"] : [],
|
|
1031
|
+
...usesHoloAuthUser ? ["import type { AuthUser as HoloAuthUser } from '@holo-js/auth'"] : [],
|
|
589
1032
|
...typedPolicyEntries.map((entry, index) => {
|
|
590
1033
|
return `import type * as holoAuthorizationPolicyModule${index} from '${relativeImportPath(GENERATED_AUTHORIZATION_TYPES_PATH, entry.sourcePath)}'`;
|
|
591
1034
|
}),
|
|
@@ -600,7 +1043,7 @@ function renderGeneratedAuthorizationTypes(authorizationPolicies, authorizationA
|
|
|
600
1043
|
if (!importName || !entry.exportName) {
|
|
601
1044
|
return [
|
|
602
1045
|
` ${JSON.stringify(entry.name)}: {`,
|
|
603
|
-
" actor:
|
|
1046
|
+
" actor: HoloAuthUser",
|
|
604
1047
|
` target: object`,
|
|
605
1048
|
" classActions: {",
|
|
606
1049
|
...classActionEntries,
|
|
@@ -613,16 +1056,12 @@ function renderGeneratedAuthorizationTypes(authorizationPolicies, authorizationA
|
|
|
613
1056
|
}
|
|
614
1057
|
return [
|
|
615
1058
|
` ${JSON.stringify(entry.name)}: {`,
|
|
616
|
-
" actor:
|
|
617
|
-
` target: typeof ${importName}[${JSON.stringify(entry.exportName)}] extends
|
|
618
|
-
|
|
619
|
-
...classActionEntries,
|
|
620
|
-
" } : {",
|
|
1059
|
+
" actor: HoloAuthUser",
|
|
1060
|
+
` target: typeof ${importName}[${JSON.stringify(entry.exportName)}] extends HoloAuthorizationPolicyDefinition<infer _TName, infer TTarget, infer _TClassActions, infer _TRecordActions, infer _TActor> ? TTarget : object`,
|
|
1061
|
+
" classActions: {",
|
|
621
1062
|
...classActionEntries,
|
|
622
1063
|
" }",
|
|
623
|
-
|
|
624
|
-
...recordActionEntries,
|
|
625
|
-
" } : {",
|
|
1064
|
+
" recordActions: {",
|
|
626
1065
|
...recordActionEntries,
|
|
627
1066
|
" }",
|
|
628
1067
|
" }"
|
|
@@ -631,19 +1070,19 @@ function renderGeneratedAuthorizationTypes(authorizationPolicies, authorizationA
|
|
|
631
1070
|
const abilityMembers = authorizationAbilities.map((entry) => {
|
|
632
1071
|
const importName = abilityImportNameByName.get(entry.name);
|
|
633
1072
|
if (!importName || !entry.exportName) {
|
|
634
|
-
return ` ${JSON.stringify(entry.name)}: { actor:
|
|
1073
|
+
return ` ${JSON.stringify(entry.name)}: { actor: HoloAuthUser, input: object }`;
|
|
635
1074
|
}
|
|
636
1075
|
return [
|
|
637
1076
|
` ${JSON.stringify(entry.name)}: {`,
|
|
638
|
-
" actor:
|
|
639
|
-
` input: typeof ${importName}[${JSON.stringify(entry.exportName)}] extends
|
|
1077
|
+
" actor: HoloAuthUser",
|
|
1078
|
+
` input: typeof ${importName}[${JSON.stringify(entry.exportName)}] extends HoloAuthorizationAbilityDefinition<infer _TName, infer TInput, infer _TActor> ? TInput : object`,
|
|
640
1079
|
" }"
|
|
641
1080
|
].join("\n");
|
|
642
1081
|
});
|
|
643
1082
|
const guardMembers = guardNames.map((name) => {
|
|
644
1083
|
return [
|
|
645
1084
|
` ${JSON.stringify(name)}: {`,
|
|
646
|
-
|
|
1085
|
+
" user: HoloAuthUser",
|
|
647
1086
|
" }"
|
|
648
1087
|
].join("\n");
|
|
649
1088
|
});
|
|
@@ -663,20 +1102,23 @@ function renderGeneratedAuthorizationTypes(authorizationPolicies, authorizationA
|
|
|
663
1102
|
""
|
|
664
1103
|
].join("\n");
|
|
665
1104
|
}
|
|
666
|
-
function
|
|
1105
|
+
function renderGeneratedTsconfigForBase(basePath) {
|
|
667
1106
|
return `${JSON.stringify({
|
|
668
|
-
extends:
|
|
1107
|
+
extends: basePath,
|
|
669
1108
|
include: ["./**/*.ts", "./**/*.d.ts"]
|
|
670
1109
|
}, null, 2)}
|
|
671
1110
|
`;
|
|
672
1111
|
}
|
|
1112
|
+
async function resolveGeneratedTsconfigBase(_projectRoot) {
|
|
1113
|
+
return "../../tsconfig.json";
|
|
1114
|
+
}
|
|
673
1115
|
function getConfigExtensionPriority(fileName) {
|
|
674
1116
|
const extension = extname(fileName);
|
|
675
1117
|
const index = CONFIG_EXTENSION_PRIORITY.indexOf(extension);
|
|
676
1118
|
return index >= 0 ? index : Number.MAX_SAFE_INTEGER;
|
|
677
1119
|
}
|
|
678
1120
|
async function collectProjectConfigEntries(projectRoot) {
|
|
679
|
-
const configDir =
|
|
1121
|
+
const configDir = resolve3(projectRoot, "config");
|
|
680
1122
|
const entries = await readdir(configDir, { withFileTypes: true }).catch(() => []);
|
|
681
1123
|
const selectedByName = /* @__PURE__ */ new Map();
|
|
682
1124
|
for (const entry of entries) {
|
|
@@ -701,7 +1143,7 @@ async function collectProjectConfigEntries(projectRoot) {
|
|
|
701
1143
|
}));
|
|
702
1144
|
}
|
|
703
1145
|
function renderGeneratedConfigTypes(projectRoot, entries) {
|
|
704
|
-
const customEntries = entries.filter((entry) => !["app", "database", "redis", "cache", "storage", "queue", "broadcast", "notifications", "mail", "media", "session", "security", "auth"].includes(entry.configName));
|
|
1146
|
+
const customEntries = entries.filter((entry) => !["app", "database", "redis", "cache", "cors", "storage", "queue", "broadcast", "notifications", "mail", "media", "session", "security", "auth"].includes(entry.configName));
|
|
705
1147
|
if (customEntries.length === 0) {
|
|
706
1148
|
return [
|
|
707
1149
|
"// Generated by holo prepare. Do not edit.",
|
|
@@ -733,27 +1175,31 @@ function renderGeneratedConfigTypes(projectRoot, entries) {
|
|
|
733
1175
|
""
|
|
734
1176
|
].join("\n");
|
|
735
1177
|
}
|
|
736
|
-
async function
|
|
1178
|
+
async function writeFileIfChanged2(path, contents) {
|
|
737
1179
|
try {
|
|
738
|
-
if (await
|
|
1180
|
+
if (await readFile2(path, "utf8") === contents) {
|
|
739
1181
|
return;
|
|
740
1182
|
}
|
|
741
1183
|
} catch {
|
|
742
1184
|
}
|
|
743
|
-
await
|
|
744
|
-
await
|
|
1185
|
+
await mkdir2(dirname3(path), { recursive: true });
|
|
1186
|
+
await writeFile2(path, contents, "utf8");
|
|
745
1187
|
}
|
|
746
1188
|
function stripGeneratedAt(registry) {
|
|
747
1189
|
const { generatedAt: _generatedAt, ...stableRegistry } = registry;
|
|
748
1190
|
return stableRegistry;
|
|
749
1191
|
}
|
|
750
1192
|
async function ensureGeneratedRegistryOwnership(projectRoot) {
|
|
751
|
-
await
|
|
752
|
-
await
|
|
753
|
-
await writeFileIfChanged(resolve2(projectRoot, GENERATED_TSCONFIG_PATH), renderGeneratedTsconfig());
|
|
1193
|
+
await mkdir2(resolve3(projectRoot, GENERATED_ROOT), { recursive: true });
|
|
1194
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_GITIGNORE_PATH), "*\n!.gitignore\n");
|
|
754
1195
|
}
|
|
755
1196
|
async function writeGeneratedProjectRegistry(projectRoot, registry) {
|
|
756
1197
|
await ensureGeneratedRegistryOwnership(projectRoot);
|
|
1198
|
+
const tsconfigPath = resolve3(projectRoot, GENERATED_TSCONFIG_PATH);
|
|
1199
|
+
await writeFileIfChanged2(
|
|
1200
|
+
tsconfigPath,
|
|
1201
|
+
renderGeneratedTsconfigForBase(await resolveGeneratedTsconfigBase(projectRoot))
|
|
1202
|
+
);
|
|
757
1203
|
const loadedConfig = await loadConfigDirectory(projectRoot);
|
|
758
1204
|
const configEntries = await collectProjectConfigEntries(projectRoot);
|
|
759
1205
|
const existingRegistry = await loadGeneratedProjectRegistry(projectRoot);
|
|
@@ -761,34 +1207,41 @@ async function writeGeneratedProjectRegistry(projectRoot, registry) {
|
|
|
761
1207
|
...registry,
|
|
762
1208
|
generatedAt: existingRegistry.generatedAt
|
|
763
1209
|
} : registry;
|
|
764
|
-
await
|
|
1210
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_METADATA_PATH), renderGeneratedModule("metadata", {
|
|
765
1211
|
version: nextRegistry.version,
|
|
766
1212
|
generatedAt: nextRegistry.generatedAt,
|
|
767
1213
|
paths: nextRegistry.paths
|
|
768
1214
|
}));
|
|
769
|
-
await
|
|
770
|
-
await
|
|
771
|
-
await
|
|
772
|
-
await
|
|
773
|
-
await
|
|
774
|
-
await
|
|
775
|
-
await
|
|
776
|
-
await
|
|
777
|
-
await
|
|
778
|
-
await
|
|
779
|
-
await
|
|
780
|
-
await
|
|
781
|
-
await
|
|
782
|
-
await
|
|
783
|
-
await
|
|
784
|
-
await
|
|
1215
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_MODELS_PATH), renderGeneratedModule("models", nextRegistry.models));
|
|
1216
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_MODEL_TYPES_PATH), renderGeneratedModelTypes(nextRegistry.models));
|
|
1217
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_MIGRATIONS_PATH), renderGeneratedModule("migrations", nextRegistry.migrations));
|
|
1218
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_SEEDERS_PATH), renderGeneratedModule("seeders", nextRegistry.seeders));
|
|
1219
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_COMMANDS_PATH), renderGeneratedModule("commands", nextRegistry.commands));
|
|
1220
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_JOBS_PATH), renderGeneratedModule("jobs", nextRegistry.jobs));
|
|
1221
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_EVENTS_PATH), renderGeneratedModule("events", nextRegistry.events));
|
|
1222
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_LISTENERS_PATH), renderGeneratedModule("listeners", nextRegistry.listeners));
|
|
1223
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_BROADCAST_PATH), renderGeneratedModule("broadcast", nextRegistry.broadcast));
|
|
1224
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_CHANNELS_PATH), renderGeneratedModule("channels", nextRegistry.channels));
|
|
1225
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_BROADCAST_MANIFEST_PATH), renderGeneratedBroadcastManifest(nextRegistry));
|
|
1226
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_BROADCAST_TYPES_PATH), renderGeneratedBroadcastTypes(nextRegistry.broadcast, nextRegistry.channels));
|
|
1227
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_AUTH_TYPES_PATH), renderGeneratedAuthTypes(loadedConfig?.auth?.guards ?? {}));
|
|
1228
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_CONFIG_TYPES_PATH), renderGeneratedConfigTypes(projectRoot, configEntries));
|
|
1229
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_EVENT_TYPES_PATH), renderGeneratedEventTypes(nextRegistry.events, nextRegistry.listeners));
|
|
1230
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_QUEUE_TYPES_PATH), renderGeneratedQueueTypes(nextRegistry.jobs));
|
|
1231
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_AUTHORIZATION_REGISTRY_PATH), renderGeneratedAuthorizationRegistry(nextRegistry));
|
|
1232
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_AUTHORIZATION_TYPES_PATH), renderGeneratedAuthorizationTypes(
|
|
785
1233
|
nextRegistry.authorizationPolicies,
|
|
786
1234
|
nextRegistry.authorizationAbilities,
|
|
787
1235
|
Object.keys(loadedConfig?.auth?.guards ?? {}).sort((left, right) => left.localeCompare(right))
|
|
788
1236
|
));
|
|
789
|
-
await
|
|
790
|
-
await
|
|
1237
|
+
await syncManagedFrameworkArtifacts(projectRoot);
|
|
1238
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_INDEX_PATH), renderGeneratedIndexModule());
|
|
1239
|
+
await writeFileIfChanged2(resolve3(projectRoot, GENERATED_REGISTRY_JSON_PATH), `${JSON.stringify(nextRegistry, null, 2)}
|
|
791
1240
|
`);
|
|
1241
|
+
await writeFileIfChanged2(
|
|
1242
|
+
resolve3(projectRoot, GENERATED_SCHEMA_RUNTIME_PATH),
|
|
1243
|
+
await renderGeneratedSchemaRuntimeArtifact(projectRoot, nextRegistry.paths.generatedSchema)
|
|
1244
|
+
);
|
|
792
1245
|
}
|
|
793
1246
|
function isGeneratedProjectRegistry(value) {
|
|
794
1247
|
if (isRecord(value) && isRecord(value.paths)) {
|
|
@@ -810,16 +1263,24 @@ function isGeneratedProjectRegistry(value) {
|
|
|
810
1263
|
return isRecord(value) && value.version === 1 && isRecord(value.paths) && Array.isArray(value.models) && Array.isArray(value.migrations) && Array.isArray(value.seeders) && Array.isArray(value.commands) && Array.isArray(value.jobs) && Array.isArray(value.events) && Array.isArray(value.listeners) && Array.isArray(value.broadcast) && Array.isArray(value.channels) && Array.isArray(value.authorizationPolicies) && Array.isArray(value.authorizationAbilities);
|
|
811
1264
|
}
|
|
812
1265
|
async function loadGeneratedProjectRegistry(projectRoot) {
|
|
813
|
-
const filePath =
|
|
814
|
-
|
|
815
|
-
|
|
1266
|
+
const filePath = resolve3(projectRoot, GENERATED_REGISTRY_JSON_PATH);
|
|
1267
|
+
const contents = await readFile2(filePath, "utf8").catch(() => void 0);
|
|
1268
|
+
if (contents) {
|
|
1269
|
+
try {
|
|
1270
|
+
const parsed = JSON.parse(contents);
|
|
1271
|
+
if (isGeneratedProjectRegistry(parsed)) {
|
|
1272
|
+
return parsed;
|
|
1273
|
+
}
|
|
1274
|
+
} catch {
|
|
1275
|
+
}
|
|
816
1276
|
}
|
|
817
|
-
const
|
|
818
|
-
|
|
819
|
-
|
|
1277
|
+
const generatedIndexPath = resolve3(projectRoot, GENERATED_INDEX_PATH);
|
|
1278
|
+
const generatedModule = await importProjectModule(projectRoot, generatedIndexPath).catch(() => void 0);
|
|
1279
|
+
if (isRecord(generatedModule) && isGeneratedProjectRegistry(generatedModule.registry)) {
|
|
1280
|
+
return generatedModule.registry;
|
|
820
1281
|
}
|
|
821
|
-
if (isRecord(
|
|
822
|
-
return
|
|
1282
|
+
if (isRecord(generatedModule) && isGeneratedProjectRegistry(generatedModule.default)) {
|
|
1283
|
+
return generatedModule.default;
|
|
823
1284
|
}
|
|
824
1285
|
return void 0;
|
|
825
1286
|
}
|
|
@@ -844,6 +1305,7 @@ export {
|
|
|
844
1305
|
renderMarkdownMailTemplate,
|
|
845
1306
|
resolveNameInfo,
|
|
846
1307
|
resolveArtifactPath,
|
|
1308
|
+
renderGeneratedModelTypes,
|
|
847
1309
|
writeGeneratedProjectRegistry,
|
|
848
1310
|
loadGeneratedProjectRegistry
|
|
849
1311
|
};
|