@pattern-stack/codegen 0.23.0 → 0.25.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/CHANGELOG.md +51 -1
- package/consumer-skills/integration/SKILL.md +11 -3
- package/dist/{chunk-XKWOJZZ4.js → chunk-37PILMIT.js} +4 -4
- package/dist/{chunk-2VHZ7EKC.js → chunk-5AAA4LTE.js} +2 -2
- package/dist/{chunk-42763UEE.js → chunk-6M6LZEP6.js} +2 -2
- package/dist/{chunk-AS3NAZB6.js → chunk-B7SC2V45.js} +2 -2
- package/dist/{chunk-W72PRNJY.js → chunk-BPYZCEHS.js} +2 -2
- package/dist/{chunk-FIUC6QB5.js → chunk-CKLM57IE.js} +10 -10
- package/dist/{chunk-KYR3B3OW.js → chunk-DAHWN63L.js} +26 -5
- package/dist/chunk-DAHWN63L.js.map +1 -0
- package/dist/{chunk-SH76CFAY.js → chunk-ENAR3F5S.js} +2 -2
- package/dist/{chunk-RFH7N6EP.js → chunk-FCPTHS42.js} +2 -2
- package/dist/{chunk-FFUDEIFF.js → chunk-HN5HT5WL.js} +2 -2
- package/dist/{chunk-4M66MQYA.js → chunk-K4BQQ2NN.js} +4 -2
- package/dist/chunk-K4BQQ2NN.js.map +1 -0
- package/dist/{chunk-QFUIE37H.js → chunk-KFXXOFDC.js} +4 -4
- package/dist/{chunk-O2A6XHGD.js → chunk-LLDJS7PJ.js} +2 -2
- package/dist/{chunk-JOBQ6RUU.js → chunk-LQZESSM3.js} +28 -1
- package/dist/chunk-LQZESSM3.js.map +1 -0
- package/dist/{chunk-JRQO2IOF.js → chunk-MU54DZCC.js} +27 -1
- package/dist/chunk-MU54DZCC.js.map +1 -0
- package/dist/{chunk-INO47JXD.js → chunk-PBENHIN2.js} +3 -3
- package/dist/{chunk-CLWBNXKF.js → chunk-PLUJEQLU.js} +2 -2
- package/dist/{chunk-S7C6TIIF.js → chunk-S5G3HO7N.js} +3 -1
- package/dist/chunk-S5G3HO7N.js.map +1 -0
- package/dist/{chunk-JYBFPNBJ.js → chunk-SJGEBMJT.js} +2 -2
- package/dist/{chunk-6XP2Q5SS.js → chunk-WZOPWQN2.js} +2 -2
- package/dist/{chunk-TDEHU73T.js → chunk-YIVQ7KLS.js} +46 -5
- package/dist/chunk-YIVQ7KLS.js.map +1 -0
- package/dist/runtime/base-classes/activity-entity-service.js +3 -3
- package/dist/runtime/base-classes/base-service.js +2 -2
- package/dist/runtime/base-classes/index.js +20 -20
- package/dist/runtime/base-classes/integrated-entity-service.js +3 -3
- package/dist/runtime/base-classes/knowledge-entity-service.js +3 -3
- package/dist/runtime/base-classes/lifecycle-events.js +1 -1
- package/dist/runtime/base-classes/metadata-entity-service.js +3 -3
- package/dist/runtime/subsystems/auth/auth.module.js +1 -1
- package/dist/runtime/subsystems/auth/index.js +3 -3
- package/dist/runtime/subsystems/bridge/bridge.module.js +6 -6
- package/dist/runtime/subsystems/bridge/index.js +6 -6
- package/dist/runtime/subsystems/events/events.module.js +4 -4
- package/dist/runtime/subsystems/events/generated/bus.js +3 -3
- package/dist/runtime/subsystems/events/generated/index.d.ts +2 -2
- package/dist/runtime/subsystems/events/generated/index.js +9 -3
- package/dist/runtime/subsystems/events/generated/registry.d.ts +36 -0
- package/dist/runtime/subsystems/events/generated/registry.js +1 -1
- package/dist/runtime/subsystems/events/generated/schemas.d.ts +109 -1
- package/dist/runtime/subsystems/events/generated/schemas.js +7 -1
- package/dist/runtime/subsystems/events/generated/types.d.ts +48 -2
- package/dist/runtime/subsystems/events/index.js +4 -4
- package/dist/runtime/subsystems/index.d.ts +3 -2
- package/dist/runtime/subsystems/index.js +25 -21
- package/dist/runtime/subsystems/integration/execute-integration.use-case.d.ts +11 -1
- package/dist/runtime/subsystems/integration/execute-integration.use-case.js +2 -2
- package/dist/runtime/subsystems/integration/index.d.ts +2 -1
- package/dist/runtime/subsystems/integration/index.js +10 -8
- package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.d.ts +106 -0
- package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js +1 -0
- package/dist/runtime/subsystems/integration/integration-change-emitter.protocol.js.map +1 -0
- package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js +2 -2
- package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js +2 -2
- package/dist/runtime/subsystems/integration/integration.module.js +4 -4
- package/dist/runtime/subsystems/integration/integration.tokens.d.ts +11 -1
- package/dist/runtime/subsystems/integration/integration.tokens.js +3 -1
- package/dist/runtime/subsystems/jobs/index.js +11 -11
- package/dist/runtime/subsystems/jobs/job-worker.module.js +5 -5
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +4 -4
- package/dist/runtime/subsystems/observability/index.js +3 -3
- package/dist/runtime/subsystems/observability/observability.module.js +3 -3
- package/dist/runtime/subsystems/observability/observability.service.js +2 -2
- package/dist/src/cli/index.js +300 -53
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +13 -0
- package/dist/src/index.js +7 -7
- package/package.json +1 -1
- package/runtime/base-classes/lifecycle-events.ts +39 -6
- package/runtime/subsystems/events/generated/registry.ts +27 -0
- package/runtime/subsystems/events/generated/schemas.ts +26 -0
- package/runtime/subsystems/events/generated/types.ts +52 -0
- package/runtime/subsystems/index.ts +23 -0
- package/runtime/subsystems/integration/execute-integration.use-case.ts +69 -1
- package/runtime/subsystems/integration/index.ts +6 -0
- package/runtime/subsystems/integration/integration-change-emitter.protocol.ts +107 -0
- package/runtime/subsystems/integration/integration.tokens.ts +11 -0
- package/templates/subsystem/jobs/job-orchestration.schema.ejs.t +1 -0
- package/templates/subsystem/jobs/main-hook.ejs.t +1 -1
- package/templates/subsystem/jobs/prompt.js +40 -2
- package/templates/subsystem/jobs/worker.ejs.t +47 -35
- package/dist/chunk-4M66MQYA.js.map +0 -1
- package/dist/chunk-JOBQ6RUU.js.map +0 -1
- package/dist/chunk-JRQO2IOF.js.map +0 -1
- package/dist/chunk-KYR3B3OW.js.map +0 -1
- package/dist/chunk-S7C6TIIF.js.map +0 -1
- package/dist/chunk-TDEHU73T.js.map +0 -1
- /package/dist/{chunk-XKWOJZZ4.js.map → chunk-37PILMIT.js.map} +0 -0
- /package/dist/{chunk-2VHZ7EKC.js.map → chunk-5AAA4LTE.js.map} +0 -0
- /package/dist/{chunk-42763UEE.js.map → chunk-6M6LZEP6.js.map} +0 -0
- /package/dist/{chunk-AS3NAZB6.js.map → chunk-B7SC2V45.js.map} +0 -0
- /package/dist/{chunk-W72PRNJY.js.map → chunk-BPYZCEHS.js.map} +0 -0
- /package/dist/{chunk-FIUC6QB5.js.map → chunk-CKLM57IE.js.map} +0 -0
- /package/dist/{chunk-SH76CFAY.js.map → chunk-ENAR3F5S.js.map} +0 -0
- /package/dist/{chunk-RFH7N6EP.js.map → chunk-FCPTHS42.js.map} +0 -0
- /package/dist/{chunk-FFUDEIFF.js.map → chunk-HN5HT5WL.js.map} +0 -0
- /package/dist/{chunk-QFUIE37H.js.map → chunk-KFXXOFDC.js.map} +0 -0
- /package/dist/{chunk-O2A6XHGD.js.map → chunk-LLDJS7PJ.js.map} +0 -0
- /package/dist/{chunk-INO47JXD.js.map → chunk-PBENHIN2.js.map} +0 -0
- /package/dist/{chunk-CLWBNXKF.js.map → chunk-PLUJEQLU.js.map} +0 -0
- /package/dist/{chunk-JYBFPNBJ.js.map → chunk-SJGEBMJT.js.map} +0 -0
- /package/dist/{chunk-6XP2Q5SS.js.map → chunk-WZOPWQN2.js.map} +0 -0
package/dist/src/cli/index.js
CHANGED
|
@@ -44,13 +44,13 @@ import {
|
|
|
44
44
|
validateOrchestrationProject,
|
|
45
45
|
validateProviders,
|
|
46
46
|
writeManifest
|
|
47
|
-
} from "../../chunk-
|
|
47
|
+
} from "../../chunk-K4BQQ2NN.js";
|
|
48
48
|
import "../../chunk-KVOWSC5S.js";
|
|
49
|
-
import "../../chunk-QFUIE37H.js";
|
|
50
|
-
import "../../chunk-FFUDEIFF.js";
|
|
51
|
-
import "../../chunk-EO2QPOKH.js";
|
|
52
49
|
import "../../chunk-PRWIX6UW.js";
|
|
53
|
-
import "../../chunk-
|
|
50
|
+
import "../../chunk-KFXXOFDC.js";
|
|
51
|
+
import "../../chunk-HN5HT5WL.js";
|
|
52
|
+
import "../../chunk-EO2QPOKH.js";
|
|
53
|
+
import "../../chunk-LLDJS7PJ.js";
|
|
54
54
|
import "../../chunk-HNWZFNKP.js";
|
|
55
55
|
import "../../chunk-AHV4GDYM.js";
|
|
56
56
|
import "../../chunk-SQDOBLBP.js";
|
|
@@ -63,8 +63,8 @@ import {
|
|
|
63
63
|
} from "../../chunk-5TK7MEN4.js";
|
|
64
64
|
import "../../chunk-4KNXX6TI.js";
|
|
65
65
|
import "../../chunk-3CJFPU6Q.js";
|
|
66
|
-
import "../../chunk-
|
|
67
|
-
import "../../chunk-
|
|
66
|
+
import "../../chunk-YIVQ7KLS.js";
|
|
67
|
+
import "../../chunk-S5G3HO7N.js";
|
|
68
68
|
import "../../chunk-MZ6GV4YF.js";
|
|
69
69
|
import "../../chunk-LG57S2SC.js";
|
|
70
70
|
import "../../chunk-U64T4YZE.js";
|
|
@@ -2151,7 +2151,7 @@ function loadEvents(eventsDir, entityNames) {
|
|
|
2151
2151
|
function desugarEntityEvents(entity) {
|
|
2152
2152
|
const entityName = entity.entity.name;
|
|
2153
2153
|
const entityEvents = entity.events ?? [];
|
|
2154
|
-
|
|
2154
|
+
const explicit = entityEvents.map((ev) => {
|
|
2155
2155
|
const payload = {};
|
|
2156
2156
|
for (const [key, typeString] of Object.entries(ev.body)) {
|
|
2157
2157
|
if (!isEventFieldType(typeString)) {
|
|
@@ -2173,6 +2173,56 @@ function desugarEntityEvents(entity) {
|
|
|
2173
2173
|
};
|
|
2174
2174
|
return def;
|
|
2175
2175
|
});
|
|
2176
|
+
const changeTriad = desugarEmitChangeEvents(entity);
|
|
2177
|
+
return [...explicit, ...changeTriad];
|
|
2178
|
+
}
|
|
2179
|
+
var EMIT_CHANGE_SUFFIXES = ["created", "edited", "deleted"];
|
|
2180
|
+
function desugarEmitChangeEvents(entity) {
|
|
2181
|
+
if (entity.integration?.sink?.emit_changes !== true) return [];
|
|
2182
|
+
const entityName = entity.entity.name;
|
|
2183
|
+
const basePayload = {
|
|
2184
|
+
entity_id: {
|
|
2185
|
+
type: "uuid",
|
|
2186
|
+
nullable: false,
|
|
2187
|
+
description: "Local aggregate id the sink wrote/soft-deleted."
|
|
2188
|
+
},
|
|
2189
|
+
external_id: {
|
|
2190
|
+
type: "string",
|
|
2191
|
+
nullable: false,
|
|
2192
|
+
description: "Vendor external id the change keyed on."
|
|
2193
|
+
},
|
|
2194
|
+
provider: {
|
|
2195
|
+
type: "string",
|
|
2196
|
+
nullable: false,
|
|
2197
|
+
description: "Provider label (e.g. 'slack', 'google')."
|
|
2198
|
+
},
|
|
2199
|
+
source: {
|
|
2200
|
+
type: "string",
|
|
2201
|
+
nullable: false,
|
|
2202
|
+
description: "Provenance marker \u2014 always 'integration'. A write-back action reads this to avoid echoing the change back to the vendor."
|
|
2203
|
+
}
|
|
2204
|
+
};
|
|
2205
|
+
return EMIT_CHANGE_SUFFIXES.map((suffix) => {
|
|
2206
|
+
const payload = { ...basePayload };
|
|
2207
|
+
if (suffix !== "deleted") {
|
|
2208
|
+
payload.changed_fields = {
|
|
2209
|
+
type: "json",
|
|
2210
|
+
nullable: true,
|
|
2211
|
+
description: "Differ's per-field before/after map (same value as integration_run_items.changed_fields)."
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
const def = {
|
|
2215
|
+
type: `${entityName}_${suffix}`,
|
|
2216
|
+
tier: "domain",
|
|
2217
|
+
direction: "change",
|
|
2218
|
+
aggregate: entityName,
|
|
2219
|
+
payload,
|
|
2220
|
+
retry: { attempts: 3, backoff: "exponential" },
|
|
2221
|
+
version: 1,
|
|
2222
|
+
pool: DIRECTION_TO_POOL.change
|
|
2223
|
+
};
|
|
2224
|
+
return def;
|
|
2225
|
+
});
|
|
2176
2226
|
}
|
|
2177
2227
|
function isEventFieldType(s) {
|
|
2178
2228
|
return EVENT_FIELD_TYPES.includes(s);
|
|
@@ -3696,6 +3746,97 @@ import {
|
|
|
3696
3746
|
} from "fs";
|
|
3697
3747
|
import { dirname, join as join8 } from "path";
|
|
3698
3748
|
|
|
3749
|
+
// src/cli/shared/change-emitter-emission-generator.ts
|
|
3750
|
+
function generatedBanner(sourceDesc) {
|
|
3751
|
+
return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
|
|
3752
|
+
// Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`.`;
|
|
3753
|
+
}
|
|
3754
|
+
function changeEmitterClass(entityClass) {
|
|
3755
|
+
return `${entityClass}ChangeEmitter`;
|
|
3756
|
+
}
|
|
3757
|
+
function generateChangeEmitter(input) {
|
|
3758
|
+
const mode = input.mode ?? "package";
|
|
3759
|
+
const cls = changeEmitterClass(input.entityClass);
|
|
3760
|
+
const eventsImport = subsystemsImport(mode, "events");
|
|
3761
|
+
const integrationImport = subsystemsImport(mode, "integration");
|
|
3762
|
+
const createdType = `${input.entityName}_created`;
|
|
3763
|
+
const editedType = `${input.entityName}_edited`;
|
|
3764
|
+
const deletedType = `${input.entityName}_deleted`;
|
|
3765
|
+
return `${generatedBanner(input.sourceDesc)}
|
|
3766
|
+
import { Inject, Injectable } from '@nestjs/common';
|
|
3767
|
+
import { TYPED_EVENT_BUS } from '${eventsImport}';
|
|
3768
|
+
import type {
|
|
3769
|
+
IIntegrationChangeEmitter,
|
|
3770
|
+
IntegrationChangeNotification,
|
|
3771
|
+
} from '${integrationImport}';
|
|
3772
|
+
|
|
3773
|
+
/**
|
|
3774
|
+
* Minimal publisher shape the emitter calls \u2014 decoupled from BOTH the package's
|
|
3775
|
+
* \`TypedEventBus\` (whose \`EventTypeName\` union is the package's own events) and
|
|
3776
|
+
* the consumer's generated \`TypedEventBus\` (whose union is the consumer's
|
|
3777
|
+
* events). The \`${createdType}\` / \`${editedType}\` / \`${deletedType}\` events
|
|
3778
|
+
* THIS class publishes live in the CONSUMER's registry; the structural \`publish\`
|
|
3779
|
+
* here accepts the string types without depending on either compile-time union.
|
|
3780
|
+
* The TYPED_EVENT_BUS token resolves to the consumer's generated bus at runtime
|
|
3781
|
+
* (bound by EventsModule.forRoot()), which validates the payload against the
|
|
3782
|
+
* generated event schema.
|
|
3783
|
+
*/
|
|
3784
|
+
interface ChangeEventPublisher {
|
|
3785
|
+
publish(
|
|
3786
|
+
type: string,
|
|
3787
|
+
aggregateId: string,
|
|
3788
|
+
payload: Record<string, unknown>,
|
|
3789
|
+
opts?: { tx?: unknown; metadata?: Record<string, unknown> },
|
|
3790
|
+
): Promise<void>;
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
/**
|
|
3794
|
+
* ${cls} \u2014 publishes the typed ${input.entityName} data-level change events
|
|
3795
|
+
* (\`${createdType}\` / \`${editedType}\` / \`${deletedType}\`) after the
|
|
3796
|
+
* integration orchestrator's sink write/soft-delete (EMIT-CHANGES seam).
|
|
3797
|
+
*
|
|
3798
|
+
* Bound to INTEGRATION_CHANGE_EMITTER in the ${input.entityName} integration
|
|
3799
|
+
* assembly; the orchestrator calls \`emitChange\` once per real change. The
|
|
3800
|
+
* payload carries \`source: 'integration'\` so a write-back action can detect an
|
|
3801
|
+
* integration-originated change and decline to echo it back to the vendor.
|
|
3802
|
+
*/
|
|
3803
|
+
@Injectable()
|
|
3804
|
+
export class ${cls} implements IIntegrationChangeEmitter {
|
|
3805
|
+
constructor(
|
|
3806
|
+
@Inject(TYPED_EVENT_BUS) private readonly bus: ChangeEventPublisher,
|
|
3807
|
+
) {}
|
|
3808
|
+
|
|
3809
|
+
async emitChange(notification: IntegrationChangeNotification): Promise<void> {
|
|
3810
|
+
const type =
|
|
3811
|
+
notification.action === 'created'
|
|
3812
|
+
? '${createdType}'
|
|
3813
|
+
: notification.action === 'updated'
|
|
3814
|
+
? '${editedType}'
|
|
3815
|
+
: '${deletedType}';
|
|
3816
|
+
|
|
3817
|
+
const payload: Record<string, unknown> = {
|
|
3818
|
+
entityId: notification.entityId,
|
|
3819
|
+
externalId: notification.externalId,
|
|
3820
|
+
provider: notification.provider,
|
|
3821
|
+
source: 'integration',
|
|
3822
|
+
};
|
|
3823
|
+
// changedFields is present on created/edited only (deletes are tombstones).
|
|
3824
|
+
if (notification.changedFields !== undefined) {
|
|
3825
|
+
payload['changedFields'] = notification.changedFields;
|
|
3826
|
+
}
|
|
3827
|
+
|
|
3828
|
+
await this.bus.publish(type, notification.entityId, payload, {
|
|
3829
|
+
tx: notification.tx,
|
|
3830
|
+
metadata:
|
|
3831
|
+
notification.tenantId !== undefined && notification.tenantId !== null
|
|
3832
|
+
? { tenantId: notification.tenantId }
|
|
3833
|
+
: undefined,
|
|
3834
|
+
});
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
`;
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3699
3840
|
// src/cli/shared/sink-emission-generator.ts
|
|
3700
3841
|
var USER_ID_FIELD = "userId";
|
|
3701
3842
|
function sinkNames(entityClass) {
|
|
@@ -3916,7 +4057,7 @@ export class ${n.sinkClass} extends ${n.sinkBaseClass} {
|
|
|
3916
4057
|
|
|
3917
4058
|
// src/cli/shared/assembly-emission-generator.ts
|
|
3918
4059
|
import { relative, resolve as resolve2, sep } from "path";
|
|
3919
|
-
function
|
|
4060
|
+
function generatedBanner2(sourceDesc) {
|
|
3920
4061
|
return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
|
|
3921
4062
|
// Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`.`;
|
|
3922
4063
|
}
|
|
@@ -3947,19 +4088,30 @@ function generateAssemblyModule(input) {
|
|
|
3947
4088
|
const token = integrationUseCaseToken(input.entityName, input.provider);
|
|
3948
4089
|
const moduleClass = assemblyModuleClass(input.entityName, input.provider);
|
|
3949
4090
|
const tokensImport = `../../${input.surface}-integration.tokens`;
|
|
3950
|
-
|
|
4091
|
+
const emitChanges = input.emitChanges === true;
|
|
4092
|
+
const emitterClass = changeEmitterClass(input.entityClass);
|
|
4093
|
+
const emitterImport = `../../sinks/${input.entityName}.change-emitter`;
|
|
4094
|
+
const integrationTokenImports = emitChanges ? ` INTEGRATION_CHANGE_EMITTER,
|
|
4095
|
+
INTEGRATION_CHANGE_SOURCE,
|
|
4096
|
+
INTEGRATION_SINK,` : ` INTEGRATION_CHANGE_SOURCE,
|
|
4097
|
+
INTEGRATION_SINK,`;
|
|
4098
|
+
const emitterImportLine = emitChanges ? `
|
|
4099
|
+
import { ${emitterClass} } from '${emitterImport}';` : "";
|
|
4100
|
+
const emitterProviderBlock = emitChanges ? `
|
|
4101
|
+
${emitterClass},
|
|
4102
|
+
{ provide: INTEGRATION_CHANGE_EMITTER, useExisting: ${emitterClass} },` : "";
|
|
4103
|
+
return `${generatedBanner2(input.sourceDesc)}
|
|
3951
4104
|
import { Module } from '@nestjs/common';
|
|
3952
4105
|
import {
|
|
3953
4106
|
ExecuteIntegrationUseCase,
|
|
3954
|
-
|
|
3955
|
-
INTEGRATION_SINK,
|
|
4107
|
+
${integrationTokenImports}
|
|
3956
4108
|
} from '${subsystemsImport(input.mode ?? "package", "integration")}';
|
|
3957
4109
|
import { ${adapterClass} } from '${adapterImport}';
|
|
3958
4110
|
import { ${adapterModuleClass} } from '${adapterModuleImport}';
|
|
3959
4111
|
import { ${sinkClass} } from '${sinkImport}';
|
|
3960
4112
|
import { ${input.repoClass} } from '${input.repoImportSpecifier}';
|
|
3961
4113
|
import { ${input.moduleClass} } from '${input.moduleImportSpecifier}';
|
|
3962
|
-
import { ${token} } from '${tokensImport}'
|
|
4114
|
+
import { ${token} } from '${tokensImport}';${emitterImportLine}
|
|
3963
4115
|
|
|
3964
4116
|
/**
|
|
3965
4117
|
* ${moduleClass} \u2014 the ${input.surface}/${input.entityName} \u2190 ${input.provider}
|
|
@@ -3969,7 +4121,12 @@ import { ${token} } from '${tokensImport}';
|
|
|
3969
4121
|
* \`changeSources.${input.entityName}\` and INTEGRATION_SINK from
|
|
3970
4122
|
* ${sinkClass}, provides a local ExecuteIntegrationUseCase, and aliases+exports
|
|
3971
4123
|
* it under ${token} (the bare class token is ambiguous at app root \u2014 every
|
|
3972
|
-
* assembly provides it)
|
|
4124
|
+
* assembly provides it).${emitChanges ? `
|
|
4125
|
+
*
|
|
4126
|
+
* EMIT-CHANGES: binds INTEGRATION_CHANGE_EMITTER to ${emitterClass} so the
|
|
4127
|
+
* orchestrator publishes typed ${input.entityName}_created/_edited/_deleted events
|
|
4128
|
+
* after every sink write/soft-delete (integration.sink.emit_changes).
|
|
4129
|
+
*` : ""} The substrate (cursor store, run recorder, differ,
|
|
3973
4130
|
* multi-tenant flag) comes from the global IntegrationModule.forRoot(...) in
|
|
3974
4131
|
* AppModule, never re-bound here.
|
|
3975
4132
|
*/
|
|
@@ -3985,7 +4142,7 @@ import { ${token} } from '${tokensImport}';
|
|
|
3985
4142
|
provide: INTEGRATION_SINK,
|
|
3986
4143
|
useFactory: (repo: ${input.repoClass}) => new ${sinkClass}(repo, '${input.provider}'),
|
|
3987
4144
|
inject: [${input.repoClass}],
|
|
3988
|
-
}
|
|
4145
|
+
},${emitterProviderBlock}
|
|
3989
4146
|
ExecuteIntegrationUseCase,
|
|
3990
4147
|
{ provide: ${token}, useExisting: ExecuteIntegrationUseCase },
|
|
3991
4148
|
],
|
|
@@ -4005,7 +4162,7 @@ function generateIntegrationTokens(surface, entries) {
|
|
|
4005
4162
|
* (${assemblyModuleClass(e.entityName, e.provider)}). A trigger grabs this to run it. */
|
|
4006
4163
|
export const ${token} = Symbol.for('${key}');`;
|
|
4007
4164
|
}).join("\n\n");
|
|
4008
|
-
return `${
|
|
4165
|
+
return `${generatedBanner2(`surface: ${surface}`)}
|
|
4009
4166
|
/**
|
|
4010
4167
|
* Use-case handles for the \`${surface}\` surface \u2014 one per (entity, provider)
|
|
4011
4168
|
* assembly. Each is a Symbol \`provide:\` token a per-entity
|
|
@@ -4031,7 +4188,7 @@ function generateIntegrationAggregator(surface, entries) {
|
|
|
4031
4188
|
return `import { ${cls} } from '${path36}';`;
|
|
4032
4189
|
}).join("\n");
|
|
4033
4190
|
const membersInline = moduleClasses.join(", ");
|
|
4034
|
-
return `${
|
|
4191
|
+
return `${generatedBanner2(`surface: ${surface}`)}
|
|
4035
4192
|
import { Module } from '@nestjs/common';
|
|
4036
4193
|
${importLines || "// no (entity, provider) integration assemblies on this surface yet"}
|
|
4037
4194
|
|
|
@@ -4184,7 +4341,7 @@ function isClientlessProvider(surfaces) {
|
|
|
4184
4341
|
return surfaces.length > 0 && surfaces.every((s) => SURFACE_REGISTRY[s]?.readPrimitive === true);
|
|
4185
4342
|
}
|
|
4186
4343
|
var SCAFFOLD_SENTINEL = "// <CODEGEN-SCAFFOLD-V1>";
|
|
4187
|
-
function
|
|
4344
|
+
function generatedBanner3(sourceDesc) {
|
|
4188
4345
|
return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
|
|
4189
4346
|
// Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`.`;
|
|
4190
4347
|
}
|
|
@@ -4424,7 +4581,7 @@ ${changeSourcesDecl}
|
|
|
4424
4581
|
}
|
|
4425
4582
|
function generateAdapterModule(def, surface) {
|
|
4426
4583
|
const n = names(def.slug, surface);
|
|
4427
|
-
return `${
|
|
4584
|
+
return `${generatedBanner3(`definitions/providers/${def.slug}.yaml (surface: ${surface})`)}
|
|
4428
4585
|
import { Module } from '@nestjs/common';
|
|
4429
4586
|
import { ${n.providerModuleClass} } from '../../../providers/${def.slug}/${def.slug}.provider.module';
|
|
4430
4587
|
import { ${n.adapterClass} } from './${def.slug}-${surface}.adapter';
|
|
@@ -4442,13 +4599,13 @@ function generateAdaptersBarrel(surface, providerSlugs) {
|
|
|
4442
4599
|
const n = names(slug, surface);
|
|
4443
4600
|
return `export { ${n.adapterModuleClass} } from './${slug}/${slug}-${surface}.adapter.module';`;
|
|
4444
4601
|
}).join("\n");
|
|
4445
|
-
return `${
|
|
4602
|
+
return `${generatedBanner3(`definitions/providers/*.yaml (surface: ${surface})`)}
|
|
4446
4603
|
${lines}
|
|
4447
4604
|
`;
|
|
4448
4605
|
}
|
|
4449
4606
|
function generateSurfaceTokens(surface, mode = "package") {
|
|
4450
4607
|
const n = names("__placeholder__", surface);
|
|
4451
|
-
return `${
|
|
4608
|
+
return `${generatedBanner3(`surface: ${surface}`)}
|
|
4452
4609
|
import type { IChangeSource } from '${subsystemsImport(mode, "integration")}';
|
|
4453
4610
|
|
|
4454
4611
|
/** The assembled list of every ${surface} adapter's contribution. */
|
|
@@ -4487,7 +4644,7 @@ function generateSurfaceAggregator(surface, providerSlugs, mode = "package") {
|
|
|
4487
4644
|
return `${lowerFirst(p.adapterClass)}: ${p.adapterClass}`;
|
|
4488
4645
|
}).join(", ");
|
|
4489
4646
|
const injectTokens = per.map((p) => p.adapterClass).join(", ");
|
|
4490
|
-
return `${
|
|
4647
|
+
return `${generatedBanner3(`surface: ${surface}`)}
|
|
4491
4648
|
import { Module } from '@nestjs/common';
|
|
4492
4649
|
import {
|
|
4493
4650
|
MemoryEntityChangeSourceRegistry,
|
|
@@ -4559,7 +4716,7 @@ function generateTypedView(surface, providerSlugs, entities) {
|
|
|
4559
4716
|
const providerUnion = slugs.length ? slugs.map((s) => `'${s}'`).join(" | ") : "never";
|
|
4560
4717
|
const entityUnion = ents.length ? ents.map((e) => `'${e}'`).join(" | ") : "never";
|
|
4561
4718
|
const mapEntries = slugs.map((s) => ` ${jsKey(s)}: ${surfacePascal}Entity;`).join("\n");
|
|
4562
|
-
return `${
|
|
4719
|
+
return `${generatedBanner3(`surface: ${surface}`)}
|
|
4563
4720
|
/**
|
|
4564
4721
|
* Per-consumer typed view for the \`${surface}\` surface. Surface-scoped unions
|
|
4565
4722
|
* + a (provider, entity) validity map for compile-time-checked consumer
|
|
@@ -4589,6 +4746,7 @@ function emitAdapters(opts) {
|
|
|
4589
4746
|
scaffoldsSkipped: [],
|
|
4590
4747
|
skippedSurfaces: [],
|
|
4591
4748
|
assembliesWritten: [],
|
|
4749
|
+
changeEmittersWritten: [],
|
|
4592
4750
|
tokensWritten: [],
|
|
4593
4751
|
integrationAggregatorsWritten: [],
|
|
4594
4752
|
skippedAssemblies: []
|
|
@@ -4702,6 +4860,19 @@ function emitAdapters(opts) {
|
|
|
4702
4860
|
if (!opts.dryRun) writeFile(subclassPath, subclassContent);
|
|
4703
4861
|
result.scaffoldsWritten.push(subclassPath);
|
|
4704
4862
|
}
|
|
4863
|
+
const emitChanges = def?.integration?.sink?.emit_changes === true;
|
|
4864
|
+
if (emitChanges) {
|
|
4865
|
+
const emitterPath = join8(sinksDir, `${entityName}.change-emitter.ts`);
|
|
4866
|
+
const emitterContent = generateChangeEmitter({
|
|
4867
|
+
entityName,
|
|
4868
|
+
entityClass: loc.entityClass,
|
|
4869
|
+
surface,
|
|
4870
|
+
sourceDesc: `definitions entity '${entityName}' (integration.sink.emit_changes)`,
|
|
4871
|
+
mode
|
|
4872
|
+
});
|
|
4873
|
+
if (!opts.dryRun) writeIfChanged(emitterPath, emitterContent);
|
|
4874
|
+
result.changeEmittersWritten.push(emitterPath);
|
|
4875
|
+
}
|
|
4705
4876
|
for (const slug of slugs) {
|
|
4706
4877
|
const assemblyPath = join8(
|
|
4707
4878
|
modulesDir,
|
|
@@ -4718,7 +4889,8 @@ function emitAdapters(opts) {
|
|
|
4718
4889
|
repoImportSpecifier: loc.repoImportSpecifier,
|
|
4719
4890
|
repoClass: loc.repoClass,
|
|
4720
4891
|
sourceDesc: `definitions/providers/${slug}.yaml`,
|
|
4721
|
-
mode
|
|
4892
|
+
mode,
|
|
4893
|
+
emitChanges
|
|
4722
4894
|
});
|
|
4723
4895
|
if (!opts.dryRun) writeIfChanged(assemblyPath, assemblyContent);
|
|
4724
4896
|
result.assembliesWritten.push(assemblyPath);
|
|
@@ -5052,12 +5224,12 @@ function resolveSyncMode(entity, config) {
|
|
|
5052
5224
|
// src/emitters/frontend/emit-utils.ts
|
|
5053
5225
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5054
5226
|
import { dirname as dirname3 } from "path";
|
|
5055
|
-
function
|
|
5227
|
+
function generatedBanner4(sourceDesc) {
|
|
5056
5228
|
return `// @generated by @pattern-stack/codegen from ${sourceDesc} \u2014 DO NOT EDIT.
|
|
5057
5229
|
// Hand edits are overwritten on re-emit. Regenerate with \`bun run codegen\`.`;
|
|
5058
5230
|
}
|
|
5059
5231
|
function withBanner(sourceDesc, body) {
|
|
5060
|
-
return `${
|
|
5232
|
+
return `${generatedBanner4(sourceDesc)}
|
|
5061
5233
|
|
|
5062
5234
|
${body}`;
|
|
5063
5235
|
}
|
|
@@ -6893,6 +7065,11 @@ var EntityNewCommand = class extends Command2 {
|
|
|
6893
7065
|
`integration assembly codegen: ${adapterResult.assembliesWritten.length} module(s) + ${adapterResult.tokensWritten.length} tokens file(s) + ${adapterResult.integrationAggregatorsWritten.length} aggregator(s)`
|
|
6894
7066
|
);
|
|
6895
7067
|
}
|
|
7068
|
+
if (adapterResult.changeEmittersWritten.length) {
|
|
7069
|
+
printInfo(
|
|
7070
|
+
`integration change-emitters (emit_changes): ${adapterResult.changeEmittersWritten.length} emitter(s)`
|
|
7071
|
+
);
|
|
7072
|
+
}
|
|
6896
7073
|
for (const s of adapterResult.scaffoldsSkipped) {
|
|
6897
7074
|
printInfo(`skipped scaffold ${s} (author-owned)`);
|
|
6898
7075
|
}
|
|
@@ -7231,7 +7408,7 @@ function resolveJobsScaffoldLocals(input) {
|
|
|
7231
7408
|
const { cwd, config, fileExists, readFile } = input;
|
|
7232
7409
|
const jobsBlock = config?.jobs ?? {};
|
|
7233
7410
|
const subsystemsRoot = resolveSubsystemsRootFromConfig(cwd, config);
|
|
7234
|
-
const workerPath = path16.resolve(cwd, "worker.ts");
|
|
7411
|
+
const workerPath = path16.resolve(cwd, "src", "worker.ts");
|
|
7235
7412
|
const mainTsPath = path16.resolve(cwd, "src/main.ts");
|
|
7236
7413
|
const configPath = path16.resolve(cwd, "codegen.config.yaml");
|
|
7237
7414
|
const schemaPath = path16.resolve(
|
|
@@ -7249,10 +7426,37 @@ function resolveJobsScaffoldLocals(input) {
|
|
|
7249
7426
|
configPath,
|
|
7250
7427
|
workerExists: fileExists(workerPath),
|
|
7251
7428
|
workerPath,
|
|
7429
|
+
jobWorkerModuleImport: resolveJobWorkerModuleImport(config),
|
|
7430
|
+
workerForRootOpts: resolveWorkerForRootOpts(jobsBlock),
|
|
7252
7431
|
schemaPath,
|
|
7253
|
-
mainHookInjected
|
|
7432
|
+
mainHookInjected,
|
|
7433
|
+
// #517 — in package mode the schema ships in the package (consumed via the
|
|
7434
|
+
// schema barrel), so the template is skipped; vendored mode renders it.
|
|
7435
|
+
skipSchema: resolveRuntimeMode(config) === "package"
|
|
7254
7436
|
};
|
|
7255
7437
|
}
|
|
7438
|
+
function resolveJobWorkerModuleImport(config) {
|
|
7439
|
+
return runtimeImport(resolveRuntimeMode(config), "subsystems/jobs/index");
|
|
7440
|
+
}
|
|
7441
|
+
function resolveWorkerForRootOpts(jobsBlock) {
|
|
7442
|
+
const backend = jobsBlock.backend ?? "drizzle";
|
|
7443
|
+
const parts = [`mode: 'standalone'`];
|
|
7444
|
+
if (backend === "bullmq") {
|
|
7445
|
+
parts.push(`backend: 'bullmq'`);
|
|
7446
|
+
const bullExt = jobsBlock.extensions?.bullmq;
|
|
7447
|
+
if (bullExt) {
|
|
7448
|
+
parts.push(`domainModuleExtensions: { bullmq: ${jsonToTs(bullExt)} }`);
|
|
7449
|
+
}
|
|
7450
|
+
} else {
|
|
7451
|
+
const workerExtClause = drizzleExtensionsClause(
|
|
7452
|
+
drizzleJobsExtensions(backend, jobsBlock),
|
|
7453
|
+
"domainModuleExtensions"
|
|
7454
|
+
);
|
|
7455
|
+
if (workerExtClause) parts.push(workerExtClause);
|
|
7456
|
+
}
|
|
7457
|
+
parts.push(`allPools: true`);
|
|
7458
|
+
return `{ ${parts.join(", ")} }`;
|
|
7459
|
+
}
|
|
7256
7460
|
function normaliseWorkerMode(raw) {
|
|
7257
7461
|
if (raw === "standalone") return "standalone";
|
|
7258
7462
|
return "embedded";
|
|
@@ -7260,6 +7464,9 @@ function normaliseWorkerMode(raw) {
|
|
|
7260
7464
|
function normaliseMultiTenant2(raw) {
|
|
7261
7465
|
return raw === true;
|
|
7262
7466
|
}
|
|
7467
|
+
function encodeWorkerForRootOpts(opts) {
|
|
7468
|
+
return Buffer.from(opts, "utf-8").toString("base64");
|
|
7469
|
+
}
|
|
7263
7470
|
function localsToHygenArgs2(locals) {
|
|
7264
7471
|
return [
|
|
7265
7472
|
"--appName",
|
|
@@ -7276,10 +7483,19 @@ function localsToHygenArgs2(locals) {
|
|
|
7276
7483
|
workerSkipValue(locals.workerExists),
|
|
7277
7484
|
"--workerPath",
|
|
7278
7485
|
locals.workerPath,
|
|
7486
|
+
"--jobWorkerModuleImport",
|
|
7487
|
+
locals.jobWorkerModuleImport,
|
|
7488
|
+
"--workerForRootOpts",
|
|
7489
|
+
encodeWorkerForRootOpts(locals.workerForRootOpts),
|
|
7279
7490
|
"--schemaPath",
|
|
7280
7491
|
locals.schemaPath,
|
|
7281
7492
|
"--mainHookInjected",
|
|
7282
|
-
workerSkipValue(locals.mainHookInjected)
|
|
7493
|
+
workerSkipValue(locals.mainHookInjected),
|
|
7494
|
+
// #517 — boolean-ish for `skip_if` (same '' / 'true' encoding as
|
|
7495
|
+
// workerExists / mainHookInjected). 'true' in package mode → the schema
|
|
7496
|
+
// template is skipped (the package ships the schema).
|
|
7497
|
+
"--skipSchema",
|
|
7498
|
+
workerSkipValue(locals.skipSchema)
|
|
7283
7499
|
];
|
|
7284
7500
|
}
|
|
7285
7501
|
|
|
@@ -8137,6 +8353,12 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8137
8353
|
return 1;
|
|
8138
8354
|
}
|
|
8139
8355
|
if (this.dryRun) {
|
|
8356
|
+
const jobsScaffoldDryRun = desc.name === "jobs" ? runJobsScaffold(ctx.cwd, ctx.config, {
|
|
8357
|
+
dryRun: true,
|
|
8358
|
+
json: isJsonMode(),
|
|
8359
|
+
forceConfig: this.forceConfig,
|
|
8360
|
+
skipConfigBlock: true
|
|
8361
|
+
}) : null;
|
|
8140
8362
|
if (isJsonMode()) {
|
|
8141
8363
|
printJson({
|
|
8142
8364
|
command: "subsystem install",
|
|
@@ -8144,7 +8366,8 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8144
8366
|
runtime: "package",
|
|
8145
8367
|
dryRun: true,
|
|
8146
8368
|
installList: already ? installed : [...installed, desc.name],
|
|
8147
|
-
configBlockOutcome
|
|
8369
|
+
configBlockOutcome,
|
|
8370
|
+
...jobsScaffoldDryRun ? { scaffold: jobsScaffoldDryRun } : {}
|
|
8148
8371
|
});
|
|
8149
8372
|
} else {
|
|
8150
8373
|
printInfo(`Dry run \u2014 runtime: package (no files vendored).`);
|
|
@@ -8153,6 +8376,14 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8153
8376
|
printInfo(` ${desc.name} config block would be ${configBlockOutcome}`);
|
|
8154
8377
|
}
|
|
8155
8378
|
printInfo(" would regenerate <generated>/subsystems.ts + subsystems-schema.ts");
|
|
8379
|
+
if (jobsScaffoldDryRun?.planned?.length) {
|
|
8380
|
+
printInfo(
|
|
8381
|
+
` jobs scaffold \u2014 ${jobsScaffoldDryRun.planned.length} template targets (worker + main.ts hook; schema ships in the package)`
|
|
8382
|
+
);
|
|
8383
|
+
for (const p of jobsScaffoldDryRun.planned) {
|
|
8384
|
+
console.log(` ${theme.muted(icons.arrow)} ${path24.relative(ctx.cwd, p) || p}`);
|
|
8385
|
+
}
|
|
8386
|
+
}
|
|
8156
8387
|
}
|
|
8157
8388
|
return 0;
|
|
8158
8389
|
}
|
|
@@ -8197,6 +8428,12 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8197
8428
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8198
8429
|
printWarning(`barrel regeneration failed \u2014 ${msg}`);
|
|
8199
8430
|
}
|
|
8431
|
+
const jobsScaffold = desc.name === "jobs" ? runJobsScaffold(ctx.cwd, refreshed.config, {
|
|
8432
|
+
dryRun: false,
|
|
8433
|
+
json: isJsonMode(),
|
|
8434
|
+
forceConfig: this.forceConfig,
|
|
8435
|
+
skipConfigBlock: true
|
|
8436
|
+
}) : null;
|
|
8200
8437
|
if (isJsonMode()) {
|
|
8201
8438
|
printJson({
|
|
8202
8439
|
command: "subsystem install",
|
|
@@ -8208,7 +8445,8 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8208
8445
|
installOutcome: installResult.outcome,
|
|
8209
8446
|
configBlockOutcome,
|
|
8210
8447
|
barrelEmitted,
|
|
8211
|
-
schemaEmitted
|
|
8448
|
+
schemaEmitted,
|
|
8449
|
+
...jobsScaffold ? { scaffold: jobsScaffold } : {}
|
|
8212
8450
|
});
|
|
8213
8451
|
return 0;
|
|
8214
8452
|
}
|
|
@@ -8216,6 +8454,17 @@ var SubsystemInstallCommand = class extends Command3 {
|
|
|
8216
8454
|
if (installResult.outcome === "added") {
|
|
8217
8455
|
printInfo(`Added '${desc.name}' to subsystems.install.`);
|
|
8218
8456
|
}
|
|
8457
|
+
if (jobsScaffold) {
|
|
8458
|
+
if (jobsScaffold.ok) {
|
|
8459
|
+
printSuccess(
|
|
8460
|
+
`jobs scaffold applied (emitted src/worker.ts + src/main.ts hook; schema ships in the package).`
|
|
8461
|
+
);
|
|
8462
|
+
} else {
|
|
8463
|
+
printWarning(
|
|
8464
|
+
`jobs scaffold (Hygen) failed \u2014 config + barrels were written; re-run after fixing: ${jobsScaffold.error ?? "unknown error"}`
|
|
8465
|
+
);
|
|
8466
|
+
}
|
|
8467
|
+
}
|
|
8219
8468
|
printInfo(
|
|
8220
8469
|
`Regenerated <generated>/subsystems.ts (${barrelEmitted.join(", ") || "none"}) + subsystems-schema.ts (${schemaEmitted.join(", ") || "none"}).`
|
|
8221
8470
|
);
|
|
@@ -8445,14 +8694,10 @@ function runJobsScaffold(cwd, config, opts) {
|
|
|
8445
8694
|
const planned = [
|
|
8446
8695
|
...!locals.workerExists ? [locals.workerPath] : [],
|
|
8447
8696
|
locals.mainTsPath,
|
|
8448
|
-
locals.configPath,
|
|
8449
|
-
locals.schemaPath
|
|
8697
|
+
...opts.skipConfigBlock ? [] : [locals.configPath],
|
|
8698
|
+
...locals.skipSchema ? [] : [locals.schemaPath]
|
|
8450
8699
|
];
|
|
8451
|
-
const configBlockOutcome = planConfigBlockAction(
|
|
8452
|
-
locals.configPath,
|
|
8453
|
-
"jobs",
|
|
8454
|
-
opts.forceConfig
|
|
8455
|
-
);
|
|
8700
|
+
const configBlockOutcome = opts.skipConfigBlock ? void 0 : planConfigBlockAction(locals.configPath, "jobs", opts.forceConfig);
|
|
8456
8701
|
if (configBlockOutcome === "parse-error") {
|
|
8457
8702
|
return { ok: false, planned, configBlockOutcome };
|
|
8458
8703
|
}
|
|
@@ -8475,21 +8720,23 @@ function runJobsScaffold(cwd, config, opts) {
|
|
|
8475
8720
|
configBlockOutcome
|
|
8476
8721
|
};
|
|
8477
8722
|
}
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8723
|
+
if (!opts.skipConfigBlock && configBlockOutcome) {
|
|
8724
|
+
const configResult = runConfigBlockAction({
|
|
8725
|
+
cwd,
|
|
8726
|
+
actionFolder: "jobs-config",
|
|
8727
|
+
configPath: locals.configPath,
|
|
8728
|
+
subsystem: "jobs",
|
|
8729
|
+
outcome: configBlockOutcome,
|
|
8730
|
+
json: opts.json
|
|
8731
|
+
});
|
|
8732
|
+
if (!configResult.ok) {
|
|
8733
|
+
return {
|
|
8734
|
+
ok: false,
|
|
8735
|
+
planned,
|
|
8736
|
+
error: configResult.error,
|
|
8737
|
+
configBlockOutcome
|
|
8738
|
+
};
|
|
8739
|
+
}
|
|
8493
8740
|
}
|
|
8494
8741
|
return { ok: true, planned, configBlockOutcome };
|
|
8495
8742
|
}
|