@teamscala/service-boot 0.23.525 → 0.23.527

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/package.json CHANGED
@@ -17,7 +17,6 @@
17
17
  "@teamscala/event-log": "*",
18
18
  "@teamscala/file-lock": "*",
19
19
  "@teamscala/formatters": "*",
20
- "@teamscala/generic-registry": "*",
21
20
  "@teamscala/hono-boundary": "*",
22
21
  "@teamscala/http": "*",
23
22
  "@teamscala/logger": "*",
@@ -27,6 +26,7 @@
27
26
  "@teamscala/os": "*",
28
27
  "@teamscala/publish-registry": "*",
29
28
  "@teamscala/puck-boundary": "*",
29
+ "@teamscala/puck-tree": "*",
30
30
  "@teamscala/resolver-engine": "*",
31
31
  "@teamscala/timing": "*",
32
32
  "@teamscala/tool-executor": "*",
@@ -160,8 +160,6 @@
160
160
  "./page-server-loader-graph.ts": "./src/page-server-loader-graph.ts",
161
161
  "./page-server-orpc/server-client": "./src/page-server-orpc/server-client.ts",
162
162
  "./page-server-orpc/server-client.ts": "./src/page-server-orpc/server-client.ts",
163
- "./pg-boss-handler-registry": "./src/pg-boss-handler-registry.ts",
164
- "./pg-boss-handler-registry.ts": "./src/pg-boss-handler-registry.ts",
165
163
  "./pg-boss-mount": "./src/pg-boss-mount.ts",
166
164
  "./pg-boss-mount.ts": "./src/pg-boss-mount.ts",
167
165
  "./proposal-authorized-emails": "./src/proposal-authorized-emails.ts",
@@ -190,8 +188,6 @@
190
188
  "./register-registry-page-route/apply-page-branding.ts": "./src/register-registry-page-route/apply-page-branding.ts",
191
189
  "./register-registry-page-route/captured-loader-config": "./src/register-registry-page-route/captured-loader-config.ts",
192
190
  "./register-registry-page-route/captured-loader-config.ts": "./src/register-registry-page-route/captured-loader-config.ts",
193
- "./register-registry-page-route/graph-cache": "./src/register-registry-page-route/graph-cache.ts",
194
- "./register-registry-page-route/graph-cache.ts": "./src/register-registry-page-route/graph-cache.ts",
195
191
  "./register-registry-page-route/live-loader-config": "./src/register-registry-page-route/live-loader-config.ts",
196
192
  "./register-registry-page-route/live-loader-config.ts": "./src/register-registry-page-route/live-loader-config.ts",
197
193
  "./register-registry-page-route/meta-title": "./src/register-registry-page-route/meta-title.ts",
@@ -294,5 +290,5 @@
294
290
  "repository": "https://github.com/teamgbg/service-boot",
295
291
  "sideEffects": false,
296
292
  "type": "module",
297
- "version": "0.23.525"
293
+ "version": "0.23.527"
298
294
  }
@@ -13,6 +13,7 @@ import {
13
13
  buildCertificateData,
14
14
  type CertificateData,
15
15
  } from "@teamscala/agreement-generation/agreement-certificate";
16
+ import { collectBlocks, forEachContent, type PuckData } from "@teamscala/puck-tree/collect-blocks";
16
17
  import { findFirstAgreement } from "./agreement-lookup.ts";
17
18
  import { resolveAgreementViewerDirectory } from "./resolution-caches.ts";
18
19
 
@@ -38,24 +39,15 @@ export interface SigningSession {
38
39
  certificate: CertificateData | null;
39
40
  }
40
41
 
41
- /** Every resolved region's content[] array, paired with its puck_data holder. */
42
- export function* regionContents(
42
+ export function* regionTrees(
43
43
  resolved: Record<string, unknown>,
44
- ): Generator<{ pd: { content?: unknown[] }; content: ContentBlock[] }> {
44
+ ): Generator<{ content?: unknown[] } & PuckData> {
45
45
  for (const value of Object.values(resolved)) {
46
46
  const pd = (value as { puck_data?: { content?: unknown[] } } | null)?.puck_data;
47
- const content = pd?.content;
48
- if (pd && Array.isArray(content)) {
49
- yield { pd, content: content as ContentBlock[] };
50
- }
47
+ if (pd && Array.isArray(pd.content)) yield pd as { content?: unknown[] } & PuckData;
51
48
  }
52
49
  }
53
50
 
54
- /**
55
- * Locate the agreement gate block(s) across regions. A gate is the SignIn block
56
- * in `gate` mode whose field is NOT "proposalId" (that field marks a proposal
57
- * gate); the agreement id lives in `gateContextValue`.
58
- */
59
51
  export function findAgreementGate(resolved: Record<string, unknown>): {
60
52
  agreementUuid: string;
61
53
  gateRegions: { pd: { content?: unknown[] }; content: ContentBlock[]; gateIdx: number }[];
@@ -66,17 +58,19 @@ export function findAgreementGate(resolved: Record<string, unknown>): {
66
58
  content: ContentBlock[];
67
59
  gateIdx: number;
68
60
  }[] = [];
69
- for (const { pd, content } of regionContents(resolved)) {
70
- const gateIdx = content.findIndex(
71
- (b) =>
72
- b?.type === "SignIn" &&
73
- b?.props?.mode === "gate" &&
74
- b?.props?.gateContextField !== "proposalId",
75
- );
76
- if (gateIdx < 0) continue;
77
- const uuid = content[gateIdx].props?.gateContextValue;
78
- if (typeof uuid === "string" && uuid) agreementUuid = uuid;
79
- gateRegions.push({ pd, content, gateIdx });
61
+ for (const pd of regionTrees(resolved)) {
62
+ forEachContent(pd, (content) => {
63
+ const gateIdx = (content as ContentBlock[]).findIndex(
64
+ (b) =>
65
+ b?.type === "SignIn" &&
66
+ b?.props?.mode === "gate" &&
67
+ b?.props?.gateContextField !== "proposalId",
68
+ );
69
+ if (gateIdx < 0) return;
70
+ const uuid = (content as ContentBlock[])[gateIdx].props?.gateContextValue;
71
+ if (typeof uuid === "string" && uuid) agreementUuid = uuid;
72
+ gateRegions.push({ pd, content: content as ContentBlock[], gateIdx });
73
+ });
80
74
  }
81
75
  return { agreementUuid, gateRegions };
82
76
  }
@@ -219,21 +213,12 @@ export function seedSigningBlocks(
219
213
  orgName: session.orgName,
220
214
  certificate: session.certificate,
221
215
  };
222
- const seedBlock = (block: ContentBlock): void => {
223
- if (block?.type && SIGNING_BLOCK_TYPES.has(block.type)) {
224
- block.props = { ...(block.props ?? {}), ...seed };
225
- }
226
- const props = block?.props;
227
- if (!props) return;
228
- for (const propVal of Object.values(props)) {
229
- if (!Array.isArray(propVal)) continue;
230
- for (const child of propVal) {
231
- if (child && typeof child === "object") seedBlock(child as ContentBlock);
216
+ for (const pd of regionTrees(resolved)) {
217
+ for (const block of collectBlocks(pd)) {
218
+ if (SIGNING_BLOCK_TYPES.has(block.type)) {
219
+ (block as ContentBlock).props = { ...((block.props as Record<string, unknown>) ?? {}), ...seed };
232
220
  }
233
221
  }
234
- };
235
- for (const { content } of regionContents(resolved)) {
236
- for (const block of content) seedBlock(block);
237
222
  }
238
223
  }
239
224
 
@@ -132,8 +132,8 @@ export const agreementGateConfig: ContentGateConfig = {
132
132
 
133
133
  if (hasPrePlacedGate(resolved)) {
134
134
  const { gateRegions } = findAgreementGate(resolved);
135
- for (const { pd, content, gateIdx } of gateRegions) {
136
- pd.content = content.filter((_, i) => i !== gateIdx);
135
+ for (const { content, gateIdx } of gateRegions) {
136
+ content.splice(gateIdx, 1);
137
137
  }
138
138
  }
139
139
  },
@@ -3,6 +3,8 @@
3
3
  * @status handwritten
4
4
  */
5
5
 
6
+ import { forEachContent, type PuckData } from "@teamscala/puck-tree/collect-blocks";
7
+
6
8
  export interface RosterItem {
7
9
  key: string;
8
10
  role: string;
@@ -64,17 +66,6 @@ function substitute(
64
66
  );
65
67
  }
66
68
 
67
- function slotArrays(block: Block): unknown[][] {
68
- const out: unknown[][] = [];
69
- const props = block.props;
70
- if (!props) return out;
71
- for (const v of Object.values(props)) {
72
- if (Array.isArray(v) && v.every((e) => e && typeof e === "object")) {
73
- out.push(v as unknown[]);
74
- }
75
- }
76
- return out;
77
- }
78
69
 
79
70
  function cloneForItem(template: Block, item: RosterItem): Block {
80
71
  const labels = {
@@ -119,23 +110,22 @@ function isPartyTemplate(block: Block): boolean {
119
110
  return false;
120
111
  }
121
112
 
122
- function expandArray(content: unknown[], parties: RosterItem[]): unknown[] {
123
- const out: unknown[] = [];
124
- for (const raw of content) {
125
- const block = raw as Block;
126
- // Recurse into this block's own slots first.
127
- for (const slot of slotArrays(block)) {
128
- const expanded = expandArray(slot, parties);
129
- slot.length = 0;
130
- slot.push(...expanded);
131
- }
132
- if (isPartyTemplate(block)) {
133
- for (const party of parties) out.push(cloneForItem(block, party));
134
- } else {
135
- out.push(block);
113
+ function expandTree(tree: PuckData, parties: RosterItem[]): void {
114
+ const arrays: unknown[][] = [];
115
+ forEachContent(tree, (content) => arrays.push(content));
116
+ for (const content of arrays.reverse()) {
117
+ const expanded: unknown[] = [];
118
+ for (const raw of content) {
119
+ const block = raw as Block;
120
+ if (isPartyTemplate(block)) {
121
+ for (const party of parties) expanded.push(cloneForItem(block, party));
122
+ } else {
123
+ expanded.push(block);
124
+ }
136
125
  }
126
+ content.length = 0;
127
+ content.push(...expanded);
137
128
  }
138
- return out;
139
129
  }
140
130
 
141
131
  export interface RosterMeta {
@@ -167,7 +157,7 @@ export function expandRosterTemplates(
167
157
  const pd = (value as { puck_data?: { content?: unknown[] } } | null)
168
158
  ?.puck_data;
169
159
  if (!pd || !Array.isArray(pd.content)) continue;
170
- if (parties.length > 0) pd.content = expandArray(pd.content, parties);
160
+ if (parties.length > 0) expandTree(pd as PuckData, parties);
171
161
  if (meta) substituteMeta(pd.content, meta);
172
162
  }
173
163
  }