@beignet/cli 0.0.36 → 0.0.38
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/CHANGELOG.md +27 -0
- package/README.md +36 -5
- package/dist/config.d.ts +15 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -1
- package/dist/config.js.map +1 -1
- package/dist/inspect.js +21 -17
- package/dist/inspect.js.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +27 -6
- package/dist/lint.js.map +1 -1
- package/dist/make/inbox.js +7 -7
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.d.ts +2 -1
- package/dist/make/payments.d.ts.map +1 -1
- package/dist/make/payments.js +15 -11
- package/dist/make/payments.js.map +1 -1
- package/dist/make/shared.d.ts +1 -1
- package/dist/make/shared.d.ts.map +1 -1
- package/dist/make/shared.js +49 -37
- package/dist/make/shared.js.map +1 -1
- package/dist/make/tenancy.js +8 -8
- package/dist/make/tenancy.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +27 -16
- package/dist/make.js.map +1 -1
- package/dist/operational-error-reporting.d.ts +15 -0
- package/dist/operational-error-reporting.d.ts.map +1 -0
- package/dist/operational-error-reporting.js +42 -0
- package/dist/operational-error-reporting.js.map +1 -0
- package/dist/outbox.d.ts.map +1 -1
- package/dist/outbox.js +73 -0
- package/dist/outbox.js.map +1 -1
- package/dist/provider-add.js +17 -17
- package/dist/provider-add.js.map +1 -1
- package/dist/provider-audit.d.ts.map +1 -1
- package/dist/provider-audit.js +11 -6
- package/dist/provider-audit.js.map +1 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +28 -1
- package/dist/schedule.js.map +1 -1
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +37 -4
- package/dist/task.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +6 -1
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/db/index.d.ts +1 -0
- package/dist/templates/db/index.d.ts.map +1 -1
- package/dist/templates/db/index.js.map +1 -1
- package/dist/templates/db/mysql.d.ts.map +1 -1
- package/dist/templates/db/mysql.js +16 -0
- package/dist/templates/db/mysql.js.map +1 -1
- package/dist/templates/db/postgres.d.ts.map +1 -1
- package/dist/templates/db/postgres.js +16 -0
- package/dist/templates/db/postgres.js.map +1 -1
- package/dist/templates/db/sqlite.d.ts.map +1 -1
- package/dist/templates/db/sqlite.js +16 -0
- package/dist/templates/db/sqlite.js.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +4 -3
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/server.d.ts +2 -2
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +56 -40
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.js +3 -3
- package/dist/templates/shared.js.map +1 -1
- package/dist/templates/testing.js +1 -1
- package/dist/templates/todos.js +6 -6
- package/package.json +4 -4
- package/src/config.ts +66 -2
- package/src/inspect.ts +31 -19
- package/src/lint.ts +35 -4
- package/src/make/inbox.ts +7 -7
- package/src/make/payments.ts +23 -15
- package/src/make/shared.ts +56 -40
- package/src/make/tenancy.ts +8 -8
- package/src/make.ts +30 -16
- package/src/operational-error-reporting.ts +60 -0
- package/src/outbox.ts +77 -0
- package/src/provider-add.ts +21 -17
- package/src/provider-audit.ts +28 -11
- package/src/schedule.ts +32 -1
- package/src/task.ts +41 -4
- package/src/templates/base.ts +6 -1
- package/src/templates/db/index.ts +1 -0
- package/src/templates/db/mysql.ts +16 -0
- package/src/templates/db/postgres.ts +16 -0
- package/src/templates/db/sqlite.ts +16 -0
- package/src/templates/index.ts +4 -3
- package/src/templates/server.ts +56 -42
- package/src/templates/shared.ts +3 -3
- package/src/templates/testing.ts +1 -1
- package/src/templates/todos.ts +6 -6
package/src/make/shared.ts
CHANGED
|
@@ -273,7 +273,7 @@ export type FileChangeSet = {
|
|
|
273
273
|
* A provider-backed app port a generator depends on.
|
|
274
274
|
*
|
|
275
275
|
* Generated code that publishes events or sends notifications needs the
|
|
276
|
-
* matching port in `AppPorts`, the key deferred in `infra/
|
|
276
|
+
* matching port in `AppPorts`, the key deferred in `infra/port-wiring.ts`, and a
|
|
277
277
|
* dev-default provider registered in `server/providers.ts`. Wiring is
|
|
278
278
|
* generation-time by design: the starter stays lean and each generator wires
|
|
279
279
|
* its own dependencies.
|
|
@@ -434,8 +434,13 @@ export function wireListenersProviderSource(
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
if (!new RegExp(`\\bconst\\s+${providerName}\\b`).test(next)) {
|
|
437
|
+
next = addNamedImport(
|
|
438
|
+
next,
|
|
439
|
+
"tryReportException",
|
|
440
|
+
"@beignet/core/error-reporting",
|
|
441
|
+
);
|
|
437
442
|
const providerDefinition = `const ${providerName} = createProvider<
|
|
438
|
-
\tPick<AppPorts, "eventBus" | "logger">,
|
|
443
|
+
\tPick<AppPorts, "errorReporter" | "eventBus" | "logger">,
|
|
439
444
|
\tAppContext,
|
|
440
445
|
\tAppServiceContextInput
|
|
441
446
|
>()({
|
|
@@ -451,6 +456,20 @@ export function wireListenersProviderSource(
|
|
|
451
456
|
\t\t\t\t\terror,
|
|
452
457
|
\t\t\t\t\tlistenerName: listener.name,
|
|
453
458
|
\t\t\t\t});
|
|
459
|
+
\t\t\t\tvoid tryReportException({
|
|
460
|
+
\t\t\t\t\treporter: ports.errorReporter,
|
|
461
|
+
\t\t\t\t\terror,
|
|
462
|
+
\t\t\t\t\treportOptions: {
|
|
463
|
+
\t\t\t\t\t\tlevel: "error",
|
|
464
|
+
\t\t\t\t\t\tmechanism: "beignet.listener",
|
|
465
|
+
\t\t\t\t\t\thandled: false,
|
|
466
|
+
\t\t\t\t\t\ttags: {
|
|
467
|
+
\t\t\t\t\t\t\t"beignet.kind": "listener",
|
|
468
|
+
\t\t\t\t\t\t\t"beignet.listener": listener.name,
|
|
469
|
+
\t\t\t\t\t\t},
|
|
470
|
+
\t\t\t\t\t\tcontexts: { listener: { name: listener.name } },
|
|
471
|
+
\t\t\t\t\t},
|
|
472
|
+
\t\t\t\t});
|
|
454
473
|
\t\t\t},
|
|
455
474
|
\t\t});
|
|
456
475
|
|
|
@@ -496,7 +515,7 @@ export async function wirePortProviders(
|
|
|
496
515
|
options: { dryRun: boolean },
|
|
497
516
|
): Promise<{ updatedFiles: string[] }> {
|
|
498
517
|
const portsFile = config.paths.ports;
|
|
499
|
-
const infrastructureFile = config.paths.
|
|
518
|
+
const infrastructureFile = config.paths.portWiring;
|
|
500
519
|
const providersFile = providersFilePath(config);
|
|
501
520
|
const manualFor = (wiring: PortProviderWiring) =>
|
|
502
521
|
`Wire the ${wiring.portKey} port manually: add ${wiring.portKey}: ${wiring.portType}; to AppPorts in ${portsFile}, defer "${wiring.portKey}" in ${infrastructureFile}, and register ${wiring.providerFactory}() from ${wiring.providerModule} in ${providersFile}.`;
|
|
@@ -536,7 +555,7 @@ export async function wirePortProviders(
|
|
|
536
555
|
);
|
|
537
556
|
if (infrastructureOriginal === undefined) {
|
|
538
557
|
throw new Error(
|
|
539
|
-
`Could not find the generated
|
|
558
|
+
`Could not find the generated port wiring file ${infrastructureFile}. ${manualFor(active[0])}`,
|
|
540
559
|
);
|
|
541
560
|
}
|
|
542
561
|
|
|
@@ -548,7 +567,7 @@ export async function wirePortProviders(
|
|
|
548
567
|
!new RegExp(`["']${wiring.portKey}["']`).test(infrastructureNext)
|
|
549
568
|
) {
|
|
550
569
|
throw new Error(
|
|
551
|
-
`Could not find the deferred port list in ${infrastructureFile}. ${manualFor(wiring)} Or restore the generated
|
|
570
|
+
`Could not find the deferred port list in ${infrastructureFile}. ${manualFor(wiring)} Or restore the generated port wiring file before running beignet ${wiring.command}.`,
|
|
552
571
|
);
|
|
553
572
|
}
|
|
554
573
|
infrastructureNext = appended;
|
|
@@ -651,7 +670,7 @@ export async function assertStandardApp(
|
|
|
651
670
|
): Promise<void> {
|
|
652
671
|
const requiredFiles = [
|
|
653
672
|
config.paths.appContext,
|
|
654
|
-
config.paths.
|
|
673
|
+
config.paths.portWiring,
|
|
655
674
|
config.paths.ports,
|
|
656
675
|
config.paths.server,
|
|
657
676
|
config.paths.useCaseBuilder,
|
|
@@ -688,7 +707,7 @@ export async function assertTestApp(
|
|
|
688
707
|
): Promise<void> {
|
|
689
708
|
const requiredFiles = [
|
|
690
709
|
config.paths.appContext,
|
|
691
|
-
config.paths.
|
|
710
|
+
config.paths.portWiring,
|
|
692
711
|
useCaseFilePath(names, config),
|
|
693
712
|
];
|
|
694
713
|
|
|
@@ -707,7 +726,7 @@ export async function assertPortApp(
|
|
|
707
726
|
targetDir: string,
|
|
708
727
|
config: ResolvedBeignetConfig,
|
|
709
728
|
): Promise<void> {
|
|
710
|
-
const requiredFiles = [config.paths.ports, config.paths.
|
|
729
|
+
const requiredFiles = [config.paths.ports, config.paths.portWiring];
|
|
711
730
|
|
|
712
731
|
for (const file of requiredFiles) {
|
|
713
732
|
try {
|
|
@@ -725,10 +744,7 @@ export async function assertAdapterApp(
|
|
|
725
744
|
names: PortNames,
|
|
726
745
|
config: ResolvedBeignetConfig,
|
|
727
746
|
): Promise<void> {
|
|
728
|
-
const requiredFiles = [
|
|
729
|
-
config.paths.infrastructurePorts,
|
|
730
|
-
portFilePath(names, config),
|
|
731
|
-
];
|
|
747
|
+
const requiredFiles = [config.paths.portWiring, portFilePath(names, config)];
|
|
732
748
|
|
|
733
749
|
for (const file of requiredFiles) {
|
|
734
750
|
try {
|
|
@@ -740,16 +756,16 @@ export async function assertAdapterApp(
|
|
|
740
756
|
}
|
|
741
757
|
}
|
|
742
758
|
|
|
743
|
-
const
|
|
744
|
-
path.join(targetDir, config.paths.
|
|
759
|
+
const portWiring = await readFile(
|
|
760
|
+
path.join(targetDir, config.paths.portWiring),
|
|
745
761
|
"utf8",
|
|
746
762
|
);
|
|
747
763
|
if (
|
|
748
|
-
!
|
|
749
|
-
!
|
|
764
|
+
!portWiring.includes(portStubEntry(names)) &&
|
|
765
|
+
!portWiring.includes(adapterEntry(names))
|
|
750
766
|
) {
|
|
751
767
|
throw new Error(
|
|
752
|
-
`Could not find the generated ${names.interfaceName} infrastructure stub in ${config.paths.
|
|
768
|
+
`Could not find the generated ${names.interfaceName} infrastructure stub in ${config.paths.portWiring}. Wire ${names.adapterFactoryName}() manually or restore the generated stub before running make adapter.`,
|
|
753
769
|
);
|
|
754
770
|
}
|
|
755
771
|
}
|
|
@@ -822,7 +838,7 @@ export async function assertServerRuntimeApp(
|
|
|
822
838
|
const requiredFiles = [
|
|
823
839
|
config.paths.appContext,
|
|
824
840
|
config.paths.server,
|
|
825
|
-
config.paths.
|
|
841
|
+
config.paths.portWiring,
|
|
826
842
|
];
|
|
827
843
|
|
|
828
844
|
for (const file of requiredFiles) {
|
|
@@ -1254,11 +1270,11 @@ export async function updateInfrastructurePortStub(
|
|
|
1254
1270
|
config: ResolvedBeignetConfig,
|
|
1255
1271
|
options: { dryRun: boolean },
|
|
1256
1272
|
): Promise<boolean> {
|
|
1257
|
-
const filePath = path.join(targetDir, config.paths.
|
|
1273
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
1258
1274
|
const original = await readFile(filePath, "utf8");
|
|
1259
1275
|
let next = original;
|
|
1260
1276
|
const portPath = portFilePath(names, config);
|
|
1261
|
-
const importLine = `import type { ${names.interfaceName} } from "${relativeModule(config.paths.
|
|
1277
|
+
const importLine = `import type { ${names.interfaceName} } from "${relativeModule(config.paths.portWiring, portPath)}";`;
|
|
1262
1278
|
|
|
1263
1279
|
if (!next.includes(importLine)) {
|
|
1264
1280
|
next = insertAfterImports(next, importLine);
|
|
@@ -1273,7 +1289,7 @@ export async function updateInfrastructurePortStub(
|
|
|
1273
1289
|
next = insertDefinePortsProperty(
|
|
1274
1290
|
next,
|
|
1275
1291
|
entry.trim(),
|
|
1276
|
-
`Could not find definePorts({ in ${config.paths.
|
|
1292
|
+
`Could not find definePorts({ in ${config.paths.portWiring}. Add the ${names.interfaceName} stub manually, or restore the generated port wiring file before running make port.`,
|
|
1277
1293
|
);
|
|
1278
1294
|
}
|
|
1279
1295
|
|
|
@@ -1288,18 +1304,18 @@ export async function updateInfrastructureAdapterWiring(
|
|
|
1288
1304
|
config: ResolvedBeignetConfig,
|
|
1289
1305
|
options: { dryRun: boolean },
|
|
1290
1306
|
): Promise<boolean> {
|
|
1291
|
-
const filePath = path.join(targetDir, config.paths.
|
|
1307
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
1292
1308
|
const original = await readFile(filePath, "utf8");
|
|
1293
1309
|
let next = original;
|
|
1294
1310
|
const adapterPath = adapterFilePath(names, config);
|
|
1295
|
-
const adapterImportLine = `import { ${names.adapterFactoryName} } from "${relativeModule(config.paths.
|
|
1311
|
+
const adapterImportLine = `import { ${names.adapterFactoryName} } from "${relativeModule(config.paths.portWiring, adapterPath)}";`;
|
|
1296
1312
|
|
|
1297
1313
|
if (!next.includes(adapterImportLine)) {
|
|
1298
1314
|
next = insertAfterImports(next, adapterImportLine);
|
|
1299
1315
|
}
|
|
1300
1316
|
|
|
1301
1317
|
const portPath = portFilePath(names, config);
|
|
1302
|
-
const portImportLine = `import type { ${names.interfaceName} } from "${relativeModule(config.paths.
|
|
1318
|
+
const portImportLine = `import type { ${names.interfaceName} } from "${relativeModule(config.paths.portWiring, portPath)}";`;
|
|
1303
1319
|
if (next.includes(portImportLine)) {
|
|
1304
1320
|
next = next.replace(`${portImportLine}\n`, "");
|
|
1305
1321
|
}
|
|
@@ -1310,7 +1326,7 @@ export async function updateInfrastructureAdapterWiring(
|
|
|
1310
1326
|
next = next.replace(stub, adapter);
|
|
1311
1327
|
} else if (!next.includes(adapter)) {
|
|
1312
1328
|
throw new Error(
|
|
1313
|
-
`Could not find the generated ${names.interfaceName} infrastructure stub in ${config.paths.
|
|
1329
|
+
`Could not find the generated ${names.interfaceName} infrastructure stub in ${config.paths.portWiring}. Wire ${names.adapterFactoryName}() manually or restore the generated stub before running make adapter.`,
|
|
1314
1330
|
);
|
|
1315
1331
|
}
|
|
1316
1332
|
|
|
@@ -1325,15 +1341,15 @@ export async function updateInfrastructurePorts(
|
|
|
1325
1341
|
config: ResolvedBeignetConfig,
|
|
1326
1342
|
options: { dryRun: boolean },
|
|
1327
1343
|
): Promise<boolean> {
|
|
1328
|
-
const filePath = path.join(targetDir, config.paths.
|
|
1344
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
1329
1345
|
const original = await readFile(filePath, "utf8");
|
|
1330
1346
|
let next = original;
|
|
1331
1347
|
const repositoryPath = path.join(
|
|
1332
|
-
path.dirname(config.paths.
|
|
1348
|
+
path.dirname(config.paths.portWiring),
|
|
1333
1349
|
names.pluralKebab,
|
|
1334
1350
|
`in-memory-${names.singularKebab}-repository.ts`,
|
|
1335
1351
|
);
|
|
1336
|
-
const importLine = `import { createInMemory${names.singularPascal}Repository } from "${relativeModule(config.paths.
|
|
1352
|
+
const importLine = `import { createInMemory${names.singularPascal}Repository } from "${relativeModule(config.paths.portWiring, repositoryPath)}";`;
|
|
1337
1353
|
|
|
1338
1354
|
if (!next.includes(importLine)) {
|
|
1339
1355
|
next = insertAfterImports(next, importLine);
|
|
@@ -1343,9 +1359,9 @@ export async function updateInfrastructurePorts(
|
|
|
1343
1359
|
if (!next.includes(repositoryConst)) {
|
|
1344
1360
|
next = replaceRequired(
|
|
1345
1361
|
next,
|
|
1346
|
-
/(\nexport const
|
|
1362
|
+
/(\nexport const initialPorts = definePorts(?:<[^>]+>)?\((?:\)\()?\{)/,
|
|
1347
1363
|
`\n${repositoryConst}\n$1`,
|
|
1348
|
-
`Could not find definePorts({ in ${config.paths.
|
|
1364
|
+
`Could not find definePorts({ in ${config.paths.portWiring}. Add ${repositoryConst} manually, or restore the generated port wiring file before running make resource.`,
|
|
1349
1365
|
);
|
|
1350
1366
|
}
|
|
1351
1367
|
|
|
@@ -1358,7 +1374,7 @@ export async function updateInfrastructurePorts(
|
|
|
1358
1374
|
next = insertDefinePortsProperty(
|
|
1359
1375
|
next,
|
|
1360
1376
|
entry.trim(),
|
|
1361
|
-
`Could not find definePorts({ in ${config.paths.
|
|
1377
|
+
`Could not find definePorts({ in ${config.paths.portWiring}. Add ${entry.trim()} to initialPorts manually, or restore the generated port wiring file before running make resource.`,
|
|
1362
1378
|
);
|
|
1363
1379
|
}
|
|
1364
1380
|
|
|
@@ -1371,7 +1387,7 @@ export async function updateInfrastructurePorts(
|
|
|
1371
1387
|
next = insertNoopUnitOfWorkProperty(
|
|
1372
1388
|
next,
|
|
1373
1389
|
transactionEntry.trim(),
|
|
1374
|
-
`Could not find the generated Unit of Work port list in ${config.paths.
|
|
1390
|
+
`Could not find the generated Unit of Work port list in ${config.paths.portWiring}. Add ${transactionEntry.trim()} manually, or restore the generated port wiring file before running make resource.`,
|
|
1375
1391
|
);
|
|
1376
1392
|
}
|
|
1377
1393
|
|
|
@@ -1386,7 +1402,7 @@ export async function updateInfrastructureGatePolicies(
|
|
|
1386
1402
|
config: ResolvedBeignetConfig,
|
|
1387
1403
|
options: { dryRun: boolean },
|
|
1388
1404
|
): Promise<boolean> {
|
|
1389
|
-
const filePath = path.join(targetDir, config.paths.
|
|
1405
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
1390
1406
|
const original = await readFile(filePath, "utf8");
|
|
1391
1407
|
let next = original;
|
|
1392
1408
|
const policyPath = path.join(
|
|
@@ -1394,7 +1410,7 @@ export async function updateInfrastructureGatePolicies(
|
|
|
1394
1410
|
names.pluralKebab,
|
|
1395
1411
|
"policy.ts",
|
|
1396
1412
|
);
|
|
1397
|
-
const importLine = `import { ${names.singularCamel}Policy } from "${relativeModule(config.paths.
|
|
1413
|
+
const importLine = `import { ${names.singularCamel}Policy } from "${relativeModule(config.paths.portWiring, policyPath)}";`;
|
|
1398
1414
|
|
|
1399
1415
|
if (!next.includes(importLine)) {
|
|
1400
1416
|
next = insertAfterImports(next, importLine);
|
|
@@ -1403,7 +1419,7 @@ export async function updateInfrastructureGatePolicies(
|
|
|
1403
1419
|
next = appendCreateGatePolicy(
|
|
1404
1420
|
next,
|
|
1405
1421
|
`${names.singularCamel}Policy`,
|
|
1406
|
-
`Could not find createGate({ policies: [...] }) in ${config.paths.
|
|
1422
|
+
`Could not find createGate({ policies: [...] }) in ${config.paths.portWiring}. Add ${names.singularCamel}Policy to the gate policies manually, or restore the generated port wiring file before running make resource --auth.`,
|
|
1407
1423
|
);
|
|
1408
1424
|
|
|
1409
1425
|
if (next === original) return false;
|
|
@@ -1713,7 +1729,7 @@ export async function updateInfrastructureDeferredPorts(
|
|
|
1713
1729
|
config: ResolvedBeignetConfig,
|
|
1714
1730
|
options: { dryRun: boolean },
|
|
1715
1731
|
): Promise<boolean> {
|
|
1716
|
-
const filePath = path.join(targetDir, config.paths.
|
|
1732
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
1717
1733
|
const original = await readFile(filePath, "utf8");
|
|
1718
1734
|
// Drizzle resources are provided by the app database provider at startup,
|
|
1719
1735
|
// so deferred-form ports files defer the new repository key. Identity-form
|
|
@@ -1745,11 +1761,11 @@ export async function updateServerTransactionPorts(
|
|
|
1745
1761
|
|
|
1746
1762
|
if (!/\bappPorts\b/.test(next)) {
|
|
1747
1763
|
throw new Error(
|
|
1748
|
-
`Could not find
|
|
1764
|
+
`Could not find initialPorts in ${config.paths.server}. Add ${names.pluralCamel}: initialPorts.${names.pluralCamel} to createTransactionPorts manually, or restore the generated server file before running make resource.`,
|
|
1749
1765
|
);
|
|
1750
1766
|
}
|
|
1751
1767
|
|
|
1752
|
-
const entry = `\t\t\t\t\t\t${names.pluralCamel}:
|
|
1768
|
+
const entry = `\t\t\t\t\t\t${names.pluralCamel}: initialPorts.${names.pluralCamel},`;
|
|
1753
1769
|
next = insertDrizzleTransactionPortsProperty(
|
|
1754
1770
|
next,
|
|
1755
1771
|
entry.trim(),
|
|
@@ -3048,14 +3064,14 @@ export function adapterFilePath(
|
|
|
3048
3064
|
config: ResolvedBeignetConfig,
|
|
3049
3065
|
): string {
|
|
3050
3066
|
return path.join(
|
|
3051
|
-
path.dirname(config.paths.
|
|
3067
|
+
path.dirname(config.paths.portWiring),
|
|
3052
3068
|
names.kebab,
|
|
3053
3069
|
`${names.kebab}-adapter.ts`,
|
|
3054
3070
|
);
|
|
3055
3071
|
}
|
|
3056
3072
|
|
|
3057
3073
|
export function infrastructureDir(config: ResolvedBeignetConfig): string {
|
|
3058
|
-
return path.dirname(config.paths.
|
|
3074
|
+
return path.dirname(config.paths.portWiring);
|
|
3059
3075
|
}
|
|
3060
3076
|
|
|
3061
3077
|
export function drizzleSchemaIndexPath(config: ResolvedBeignetConfig): string {
|
package/src/make/tenancy.ts
CHANGED
|
@@ -330,7 +330,7 @@ export async function updateTenancyWiring(
|
|
|
330
330
|
if (
|
|
331
331
|
await updateWorkspaceInfrastructurePorts(targetDir, config, editOptions)
|
|
332
332
|
) {
|
|
333
|
-
updated.add(config.paths.
|
|
333
|
+
updated.add(config.paths.portWiring);
|
|
334
334
|
}
|
|
335
335
|
if (
|
|
336
336
|
await updateDrizzleSchemaIndexExports(
|
|
@@ -524,7 +524,7 @@ export async function updateWorkspaceInfrastructurePorts(
|
|
|
524
524
|
config: ResolvedBeignetConfig,
|
|
525
525
|
options: { dryRun: boolean },
|
|
526
526
|
): Promise<boolean> {
|
|
527
|
-
const filePath = path.join(targetDir, config.paths.
|
|
527
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
528
528
|
const original = await readFile(filePath, "utf8");
|
|
529
529
|
let next = original;
|
|
530
530
|
|
|
@@ -532,21 +532,21 @@ export async function updateWorkspaceInfrastructurePorts(
|
|
|
532
532
|
const appended = appendDeferredPortKey(next, portKey);
|
|
533
533
|
if (appended === next && !new RegExp(`["']${portKey}["']`).test(next)) {
|
|
534
534
|
throw new Error(
|
|
535
|
-
`Could not find the deferred port list in ${config.paths.
|
|
535
|
+
`Could not find the deferred port list in ${config.paths.portWiring}. Add "${portKey}" manually, or restore the generated port wiring file before running make tenancy.`,
|
|
536
536
|
);
|
|
537
537
|
}
|
|
538
538
|
next = appended;
|
|
539
539
|
}
|
|
540
540
|
|
|
541
541
|
const policyModule = relativeModule(
|
|
542
|
-
config.paths.
|
|
542
|
+
config.paths.portWiring,
|
|
543
543
|
path.join(config.paths.features, "workspaces/policy.ts"),
|
|
544
544
|
);
|
|
545
545
|
next = addNamedImport(next, "workspacePolicy", policyModule);
|
|
546
546
|
next = appendCreateGatePolicy(
|
|
547
547
|
next,
|
|
548
548
|
"workspacePolicy",
|
|
549
|
-
`Could not find createGate({ policies: [...] }) in ${config.paths.
|
|
549
|
+
`Could not find createGate({ policies: [...] }) in ${config.paths.portWiring}. Add workspacePolicy to the gate policies manually, or restore the generated port wiring file before running make tenancy.`,
|
|
550
550
|
);
|
|
551
551
|
|
|
552
552
|
if (next === original) return false;
|
|
@@ -2274,7 +2274,7 @@ import type {
|
|
|
2274
2274
|
\tWorkspaceMemberWithUser,
|
|
2275
2275
|
\tWorkspaceRepository,
|
|
2276
2276
|
} from "@/features/workspaces/ports";
|
|
2277
|
-
import {
|
|
2277
|
+
import { initialPorts } from "@/infra/port-wiring";
|
|
2278
2278
|
import type { AppTransactionPorts } from "@/ports";
|
|
2279
2279
|
|
|
2280
2280
|
export type MemoryWorkspacePorts = {
|
|
@@ -2468,9 +2468,9 @@ export type WorkspaceTestFixture = TestPortsFixture<
|
|
|
2468
2468
|
export function createWorkspaceFixture(): WorkspaceTestFixture {
|
|
2469
2469
|
\tconst repositories = createMemoryWorkspacePorts();
|
|
2470
2470
|
\tconst fixture = createTestPorts<AppContext["ports"], AppTransactionPorts>({
|
|
2471
|
-
\t\tbase:
|
|
2471
|
+
\t\tbase: initialPorts,
|
|
2472
2472
|
\t\toverrides: {
|
|
2473
|
-
\t\t\tgate:
|
|
2473
|
+
\t\t\tgate: initialPorts.gate,
|
|
2474
2474
|
\t\t\t...repositories,
|
|
2475
2475
|
\t\t},
|
|
2476
2476
|
\t});
|
package/src/make.ts
CHANGED
|
@@ -911,7 +911,7 @@ export async function makePort(
|
|
|
911
911
|
dryRun: Boolean(options.dryRun),
|
|
912
912
|
})
|
|
913
913
|
) {
|
|
914
|
-
updatedFiles.push(config.paths.
|
|
914
|
+
updatedFiles.push(config.paths.portWiring);
|
|
915
915
|
}
|
|
916
916
|
|
|
917
917
|
return {
|
|
@@ -957,7 +957,7 @@ export async function makeAdapter(
|
|
|
957
957
|
dryRun: Boolean(options.dryRun),
|
|
958
958
|
})
|
|
959
959
|
) {
|
|
960
|
-
updatedFiles.push(config.paths.
|
|
960
|
+
updatedFiles.push(config.paths.portWiring);
|
|
961
961
|
}
|
|
962
962
|
|
|
963
963
|
return {
|
|
@@ -1034,6 +1034,9 @@ export async function makeEvent(
|
|
|
1034
1034
|
const outboxDrainPlan = await planOutboxDrainWiring(targetDir, config, {
|
|
1035
1035
|
force: Boolean(options.force),
|
|
1036
1036
|
});
|
|
1037
|
+
await updateOutboxRegistry(targetDir, names, "events", config, {
|
|
1038
|
+
dryRun: true,
|
|
1039
|
+
});
|
|
1037
1040
|
|
|
1038
1041
|
const result = await makeFeatureArtifact({
|
|
1039
1042
|
targetDir,
|
|
@@ -1078,6 +1081,9 @@ export async function makeJob(options: MakeJobOptions): Promise<MakeJobResult> {
|
|
|
1078
1081
|
const outboxDrainPlan = await planOutboxDrainWiring(targetDir, config, {
|
|
1079
1082
|
force: Boolean(options.force),
|
|
1080
1083
|
});
|
|
1084
|
+
await updateOutboxRegistry(targetDir, names, "jobs", config, {
|
|
1085
|
+
dryRun: true,
|
|
1086
|
+
});
|
|
1081
1087
|
|
|
1082
1088
|
const result = await makeFeatureArtifact({
|
|
1083
1089
|
targetDir,
|
|
@@ -1697,7 +1703,7 @@ async function updateOutboxPortWiring(
|
|
|
1697
1703
|
changes.updatedFiles.push(config.paths.ports);
|
|
1698
1704
|
}
|
|
1699
1705
|
if (await updateOutboxInfrastructurePorts(targetDir, config, options)) {
|
|
1700
|
-
changes.updatedFiles.push(config.paths.
|
|
1706
|
+
changes.updatedFiles.push(config.paths.portWiring);
|
|
1701
1707
|
}
|
|
1702
1708
|
if (await updateOutboxDatabaseProvider(targetDir, config, options)) {
|
|
1703
1709
|
changes.updatedFiles.push(
|
|
@@ -1805,7 +1811,7 @@ async function updateOutboxInfrastructurePorts(
|
|
|
1805
1811
|
config: ResolvedBeignetConfig,
|
|
1806
1812
|
options: { dryRun: boolean },
|
|
1807
1813
|
): Promise<boolean> {
|
|
1808
|
-
const filePath = path.join(targetDir, config.paths.
|
|
1814
|
+
const filePath = path.join(targetDir, config.paths.portWiring);
|
|
1809
1815
|
const original = await readFile(filePath, "utf8");
|
|
1810
1816
|
let next = appendDeferredPortKey(original, "outbox");
|
|
1811
1817
|
next = appendDeferredPortKey(next, "outboxAdmin");
|
|
@@ -2166,7 +2172,7 @@ export async function makeOutbox(
|
|
|
2166
2172
|
...cronSecretPlan.files.map((file) => file.path),
|
|
2167
2173
|
...cronSecretPlan.skippedFiles,
|
|
2168
2174
|
config.paths.ports,
|
|
2169
|
-
config.paths.
|
|
2175
|
+
config.paths.portWiring,
|
|
2170
2176
|
path.join(infrastructureDir(config), "db/provider.ts"),
|
|
2171
2177
|
drizzleRepositoriesPath(config),
|
|
2172
2178
|
outboxDrizzleSchemaFilePath(config),
|
|
@@ -2361,19 +2367,19 @@ async function updateResourceWiring(
|
|
|
2361
2367
|
persistence === "memory" &&
|
|
2362
2368
|
(await updateInfrastructurePorts(targetDir, names, config, options))
|
|
2363
2369
|
) {
|
|
2364
|
-
updated.add(config.paths.
|
|
2370
|
+
updated.add(config.paths.portWiring);
|
|
2365
2371
|
}
|
|
2366
2372
|
if (
|
|
2367
2373
|
generationOptions.auth &&
|
|
2368
2374
|
(await updateInfrastructureGatePolicies(targetDir, names, config, options))
|
|
2369
2375
|
) {
|
|
2370
|
-
updated.add(config.paths.
|
|
2376
|
+
updated.add(config.paths.portWiring);
|
|
2371
2377
|
}
|
|
2372
2378
|
if (
|
|
2373
2379
|
persistence === "drizzle" &&
|
|
2374
2380
|
(await updateInfrastructureDeferredPorts(targetDir, names, config, options))
|
|
2375
2381
|
) {
|
|
2376
|
-
updated.add(config.paths.
|
|
2382
|
+
updated.add(config.paths.portWiring);
|
|
2377
2383
|
}
|
|
2378
2384
|
if (
|
|
2379
2385
|
persistence === "drizzle" &&
|
|
@@ -3381,7 +3387,13 @@ async function updateOutboxRegistry(
|
|
|
3381
3387
|
importLine,
|
|
3382
3388
|
);
|
|
3383
3389
|
|
|
3384
|
-
if (appended.kind === "missing"
|
|
3390
|
+
if (appended.kind === "missing") {
|
|
3391
|
+
throw new Error(
|
|
3392
|
+
`Could not find the ${kind} array in ${config.paths.outbox}. Register ${registryName} manually, or restore the generated outbox file before running this command.`,
|
|
3393
|
+
);
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
if (appended.kind === "unchanged") {
|
|
3385
3397
|
return "skipped";
|
|
3386
3398
|
}
|
|
3387
3399
|
|
|
@@ -3988,6 +4000,7 @@ export const outboxMessages = mysqlTable(
|
|
|
3988
4000
|
\t\tkind: varchar("kind", { length: 32 }).notNull(),
|
|
3989
4001
|
\t\tname: varchar("name", { length: 255 }).notNull(),
|
|
3990
4002
|
\t\tpayloadJson: longtext("payload_json").notNull(),
|
|
4003
|
+
\t\ttraceContextJson: longtext("trace_context_json"),
|
|
3991
4004
|
\t\tstatus: varchar("status", { length: 32 }).notNull(),
|
|
3992
4005
|
\t\tattempts: int("attempts").notNull().default(0),
|
|
3993
4006
|
\t\tmaxAttempts: int("max_attempts").notNull().default(3),
|
|
@@ -4023,6 +4036,7 @@ export const outboxMessages = ${dialect.tableFunction}(
|
|
|
4023
4036
|
\t\tkind: text("kind").notNull(),
|
|
4024
4037
|
\t\tname: text("name").notNull(),
|
|
4025
4038
|
\t\tpayloadJson: text("payload_json").notNull(),
|
|
4039
|
+
\t\ttraceContextJson: text("trace_context_json"),
|
|
4026
4040
|
\t\tstatus: text("status").notNull(),
|
|
4027
4041
|
\t\tattempts: integer("attempts").notNull().default(0),
|
|
4028
4042
|
\t\tmaxAttempts: integer("max_attempts").notNull().default(3),
|
|
@@ -4503,15 +4517,15 @@ import { createInMemoryDevtools } from "@beignet/devtools";
|
|
|
4503
4517
|
import { createTestContextFactory, createTestPorts } from "@beignet/core/testing";
|
|
4504
4518
|
import { createTestAnonymousActor } from "@beignet/core/testing";
|
|
4505
4519
|
import type { AppContext } from "${aliasModule(config.paths.appContext)}";
|
|
4506
|
-
import {
|
|
4520
|
+
import { initialPorts } from "${aliasModule(config.paths.portWiring)}";
|
|
4507
4521
|
import { ${names.exportName} } from "${relativeModule(filePath, useCaseFilePath(names, config))}";
|
|
4508
4522
|
|
|
4509
4523
|
describe("${names.exportName}", () => {
|
|
4510
4524
|
it("runs ${names.action.camel}", async () => {
|
|
4511
4525
|
const testFixture = createTestPorts<AppContext["ports"]>({
|
|
4512
|
-
base:
|
|
4526
|
+
base: initialPorts,
|
|
4513
4527
|
overrides: {
|
|
4514
|
-
gate:
|
|
4528
|
+
gate: initialPorts.gate,
|
|
4515
4529
|
devtools: createInMemoryDevtools(),
|
|
4516
4530
|
},
|
|
4517
4531
|
});
|
|
@@ -5276,7 +5290,7 @@ function testFile(
|
|
|
5276
5290
|
options: ResourceGenerationOptions,
|
|
5277
5291
|
): string {
|
|
5278
5292
|
const repositoryPath = path.join(
|
|
5279
|
-
path.dirname(config.paths.
|
|
5293
|
+
path.dirname(config.paths.portWiring),
|
|
5280
5294
|
names.pluralKebab,
|
|
5281
5295
|
`in-memory-${names.singularKebab}-repository.ts`,
|
|
5282
5296
|
);
|
|
@@ -5294,7 +5308,7 @@ import { createInMemoryDevtools } from "@beignet/devtools";
|
|
|
5294
5308
|
import { createTestContextFactory, createTestPorts } from "@beignet/core/testing";
|
|
5295
5309
|
import { ${options.auth ? "createTestUserActor" : "createTestAnonymousActor"}${options.tenant ? ", createTestTenant" : ""} } from "@beignet/core/testing";
|
|
5296
5310
|
import type { AppContext } from "${aliasModule(config.paths.appContext)}";
|
|
5297
|
-
import {
|
|
5311
|
+
import { initialPorts } from "${aliasModule(config.paths.portWiring)}";
|
|
5298
5312
|
import { appContext } from "${aliasModule(serverContextPath)}";
|
|
5299
5313
|
import {
|
|
5300
5314
|
create${names.singularPascal},
|
|
@@ -5334,7 +5348,7 @@ ${options.tenant ? `\t\t\t\ttenantId: "tenant_test",\n` : ""} name: "Gamma ${
|
|
|
5334
5348
|
${options.tenant ? `\t\t\t{\n\t\t\t\tid: "00000000-0000-4000-8000-000000000104",\n\t\t\t\ttenantId: "tenant_other",\n\t\t\t\tname: "Other Tenant ${names.singularPascal}",\n\t\t\t\tversion: 1,\n\t\t\t\tcreatedAt: "2024-01-04T00:00:00.000Z",\n\t\t\t\tupdatedAt: "2024-01-04T00:00:00.000Z",\n\t\t\t},\n` : ""} ];
|
|
5335
5349
|
const ${names.pluralCamel} = createInMemory${names.singularPascal}Repository(seed${names.pluralPascal});
|
|
5336
5350
|
const testFixture = createTestPorts<AppContext["ports"]>({
|
|
5337
|
-
base:
|
|
5351
|
+
base: initialPorts,
|
|
5338
5352
|
overrides: {
|
|
5339
5353
|
${names.pluralCamel},
|
|
5340
5354
|
${
|
|
@@ -5345,7 +5359,7 @@ ${
|
|
|
5345
5359
|
${options.tenant ? `\t\t\t\t\t\tsession: { tenantId: "tenant_test" },\n` : ""}
|
|
5346
5360
|
}),
|
|
5347
5361
|
},
|
|
5348
|
-
${options.auth ? `\t\t\t\tgate:
|
|
5362
|
+
${options.auth ? `\t\t\t\tgate: initialPorts.gate,\n` : ""}
|
|
5349
5363
|
`
|
|
5350
5364
|
: `\t\t\t\tauth: {
|
|
5351
5365
|
getSession: async () => null,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ErrorReporterPort,
|
|
3
|
+
ErrorReportOptions,
|
|
4
|
+
} from "@beignet/core/error-reporting";
|
|
5
|
+
|
|
6
|
+
export type OperationalErrorReportingContext = {
|
|
7
|
+
requestId?: string;
|
|
8
|
+
traceId?: string;
|
|
9
|
+
ports?: {
|
|
10
|
+
errorReporter?: ErrorReporterPort;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function reportOperationalFailure(args: {
|
|
15
|
+
ctx: OperationalErrorReportingContext;
|
|
16
|
+
error: unknown;
|
|
17
|
+
reportOptions: ErrorReportOptions;
|
|
18
|
+
}): Promise<void> {
|
|
19
|
+
const reporter = args.ctx.ports?.errorReporter;
|
|
20
|
+
if (!reporter) return;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const { tryReportException } = await import(
|
|
24
|
+
"@beignet/core/error-reporting"
|
|
25
|
+
);
|
|
26
|
+
await tryReportException({
|
|
27
|
+
reporter,
|
|
28
|
+
error: args.error,
|
|
29
|
+
reportOptions: {
|
|
30
|
+
requestId: args.ctx.requestId,
|
|
31
|
+
traceId: args.ctx.traceId,
|
|
32
|
+
...args.reportOptions,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
} catch {
|
|
36
|
+
// Reporting must not replace the operational command failure.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function flushOperationalErrorReporter(
|
|
41
|
+
ctx: OperationalErrorReportingContext,
|
|
42
|
+
timeoutMs = 1000,
|
|
43
|
+
): Promise<void> {
|
|
44
|
+
const reporter = ctx.ports?.errorReporter;
|
|
45
|
+
if (!reporter) return;
|
|
46
|
+
|
|
47
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
48
|
+
try {
|
|
49
|
+
await Promise.race([
|
|
50
|
+
reporter.flush({ timeoutMs }),
|
|
51
|
+
new Promise<boolean>((resolve) => {
|
|
52
|
+
timeout = setTimeout(() => resolve(false), timeoutMs);
|
|
53
|
+
}),
|
|
54
|
+
]);
|
|
55
|
+
} catch {
|
|
56
|
+
// Reporting shutdown must not replace the operational command result.
|
|
57
|
+
} finally {
|
|
58
|
+
if (timeout !== undefined) clearTimeout(timeout);
|
|
59
|
+
}
|
|
60
|
+
}
|