@openhi/constructs 0.0.91 → 0.0.92
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/lib/chunk-MLTYFMSE.mjs +807 -0
- package/lib/chunk-MLTYFMSE.mjs.map +1 -0
- package/lib/index.d.mts +42 -1
- package/lib/index.d.ts +43 -2
- package/lib/index.js +266 -179
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +267 -181
- package/lib/index.mjs.map +1 -1
- package/lib/post-confirmation.handler.d.mts +5 -0
- package/lib/post-confirmation.handler.d.ts +5 -0
- package/lib/post-confirmation.handler.js +949 -0
- package/lib/post-confirmation.handler.js.map +1 -0
- package/lib/post-confirmation.handler.mjs +128 -0
- package/lib/post-confirmation.handler.mjs.map +1 -0
- package/lib/rest-api-lambda.handler.mjs +12 -804
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SHARD_COUNT,
|
|
3
|
+
computeShard,
|
|
4
|
+
defaultTableName,
|
|
5
|
+
dynamoClient,
|
|
6
|
+
getDynamoControlService
|
|
7
|
+
} from "./chunk-MLTYFMSE.mjs";
|
|
1
8
|
import "./chunk-3QS3WKRC.mjs";
|
|
2
9
|
|
|
3
10
|
// src/data/lambda/rest-api-lambda.handler.ts
|
|
@@ -124,805 +131,6 @@ function decompressResource(compressedOrRaw) {
|
|
|
124
131
|
return compressedOrRaw;
|
|
125
132
|
}
|
|
126
133
|
|
|
127
|
-
// src/data/dynamo/dynamo-control-service.ts
|
|
128
|
-
import { Service } from "electrodb";
|
|
129
|
-
|
|
130
|
-
// src/data/dynamo/dynamo-client.ts
|
|
131
|
-
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
132
|
-
var defaultTableName = process.env.DYNAMO_TABLE_NAME ?? "jesttesttable";
|
|
133
|
-
var dynamoClient = new DynamoDBClient({
|
|
134
|
-
...process.env.MOCK_DYNAMODB_ENDPOINT && {
|
|
135
|
-
endpoint: process.env.MOCK_DYNAMODB_ENDPOINT,
|
|
136
|
-
sslEnabled: false,
|
|
137
|
-
region: "local"
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// src/data/dynamo/entities/control/configuration-entity.ts
|
|
142
|
-
import { Entity } from "electrodb";
|
|
143
|
-
|
|
144
|
-
// src/data/dynamo/shard.ts
|
|
145
|
-
var SHARD_COUNT = 4;
|
|
146
|
-
function computeShard(id) {
|
|
147
|
-
let hash = 2166136261;
|
|
148
|
-
for (let i = 0; i < id.length; i++) {
|
|
149
|
-
hash ^= id.charCodeAt(i);
|
|
150
|
-
hash = Math.imul(hash, 16777619);
|
|
151
|
-
}
|
|
152
|
-
return (hash >>> 0) % SHARD_COUNT;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// src/data/dynamo/entities/control/control-entity-common.ts
|
|
156
|
-
var gsi1ShardAttribute = {
|
|
157
|
-
type: "string",
|
|
158
|
-
watch: ["id"],
|
|
159
|
-
set: (_val, item) => {
|
|
160
|
-
if (typeof item?.id !== "string" || item.id.length === 0) {
|
|
161
|
-
return void 0;
|
|
162
|
-
}
|
|
163
|
-
return String(computeShard(item.id));
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// src/data/dynamo/entities/control/configuration-entity.ts
|
|
168
|
-
var ConfigurationEntity = new Entity({
|
|
169
|
-
model: {
|
|
170
|
-
entity: "configuration",
|
|
171
|
-
service: "control",
|
|
172
|
-
version: "01"
|
|
173
|
-
},
|
|
174
|
-
attributes: {
|
|
175
|
-
/** Sort key. "CURRENT" for current version; version history in S3. */
|
|
176
|
-
sk: {
|
|
177
|
-
type: "string",
|
|
178
|
-
required: true,
|
|
179
|
-
default: "CURRENT"
|
|
180
|
-
},
|
|
181
|
-
/** Tenant scope. Use "BASELINE" when the config is baseline default (no tenant). */
|
|
182
|
-
tenantId: {
|
|
183
|
-
type: "string",
|
|
184
|
-
required: true,
|
|
185
|
-
default: "BASELINE"
|
|
186
|
-
},
|
|
187
|
-
/** Workspace scope. Use "-" when absent. */
|
|
188
|
-
workspaceId: {
|
|
189
|
-
type: "string",
|
|
190
|
-
required: true,
|
|
191
|
-
default: "-"
|
|
192
|
-
},
|
|
193
|
-
/** User scope. Use "-" when absent. */
|
|
194
|
-
userId: {
|
|
195
|
-
type: "string",
|
|
196
|
-
required: true,
|
|
197
|
-
default: "-"
|
|
198
|
-
},
|
|
199
|
-
/** Role scope. Use "-" when absent. */
|
|
200
|
-
roleId: {
|
|
201
|
-
type: "string",
|
|
202
|
-
required: true,
|
|
203
|
-
default: "-"
|
|
204
|
-
},
|
|
205
|
-
/** Config type (category), e.g. endpoints, branding, display. */
|
|
206
|
-
key: {
|
|
207
|
-
type: "string",
|
|
208
|
-
required: true
|
|
209
|
-
},
|
|
210
|
-
/** FHIR Resource.id; logical id in URL and for the Configuration resource. */
|
|
211
|
-
id: {
|
|
212
|
-
type: "string",
|
|
213
|
-
required: true
|
|
214
|
-
},
|
|
215
|
-
/** Payload as JSON string. JSON.stringify(resource) on write; JSON.parse(item.resource) on read. */
|
|
216
|
-
resource: {
|
|
217
|
-
type: "string",
|
|
218
|
-
required: true
|
|
219
|
-
},
|
|
220
|
-
/**
|
|
221
|
-
* Summary projection (key display fields as JSON string: id, key, status).
|
|
222
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
223
|
-
*/
|
|
224
|
-
summary: {
|
|
225
|
-
type: "string",
|
|
226
|
-
required: true
|
|
227
|
-
},
|
|
228
|
-
/** Version id (e.g. ULID). Tracks current version; S3 history key. */
|
|
229
|
-
vid: {
|
|
230
|
-
type: "string",
|
|
231
|
-
required: true
|
|
232
|
-
},
|
|
233
|
-
lastUpdated: {
|
|
234
|
-
type: "string",
|
|
235
|
-
required: true
|
|
236
|
-
},
|
|
237
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
238
|
-
deleted: {
|
|
239
|
-
type: "boolean",
|
|
240
|
-
required: false
|
|
241
|
-
},
|
|
242
|
-
bundleId: {
|
|
243
|
-
type: "string",
|
|
244
|
-
required: false
|
|
245
|
-
},
|
|
246
|
-
msgId: {
|
|
247
|
-
type: "string",
|
|
248
|
-
required: false
|
|
249
|
-
}
|
|
250
|
-
},
|
|
251
|
-
indexes: {
|
|
252
|
-
/** Base table: PK, SK (data store key names). PK is built from tenantId, workspaceId, userId, roleId; SK is built from key and sk. Do not supply PK or SK from outside. */
|
|
253
|
-
record: {
|
|
254
|
-
pk: {
|
|
255
|
-
field: "PK",
|
|
256
|
-
composite: ["tenantId", "workspaceId", "userId", "roleId"],
|
|
257
|
-
template: "CONFIG#TID#${tenantId}#WID#${workspaceId}#UID#${userId}#RID#${roleId}"
|
|
258
|
-
},
|
|
259
|
-
sk: {
|
|
260
|
-
field: "SK",
|
|
261
|
-
composite: ["key", "sk"],
|
|
262
|
-
template: "KEY#${key}#SK#${sk}"
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
/**
|
|
266
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Configuration entries for a
|
|
267
|
-
* (tenant, workspace) across the four shards. Use for "list configs scoped to this tenant"
|
|
268
|
-
* (workspaceId = "-") or "list configs scoped to this workspace". Does not support
|
|
269
|
-
* hierarchical resolution in one query; use base table GetItem in fallback order
|
|
270
|
-
* (user → workspace → tenant → baseline) for that.
|
|
271
|
-
* SK is `<ISO-8601 lastUpdated>#<id>` (control-plane unlabeled per DR-004).
|
|
272
|
-
* `casing: "none"` on the SK preserves ISO-8601 `T`/`Z`.
|
|
273
|
-
*/
|
|
274
|
-
gsi1: {
|
|
275
|
-
index: "GSI1",
|
|
276
|
-
pk: {
|
|
277
|
-
field: "GSI1PK",
|
|
278
|
-
composite: ["tenantId", "workspaceId", "gsi1Shard"],
|
|
279
|
-
template: "TID#${tenantId}#WID#${workspaceId}#RT#Configuration#SHARD#${gsi1Shard}"
|
|
280
|
-
},
|
|
281
|
-
sk: {
|
|
282
|
-
field: "GSI1SK",
|
|
283
|
-
casing: "none",
|
|
284
|
-
composite: ["lastUpdated", "id"],
|
|
285
|
-
template: "${lastUpdated}#${id}"
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// src/data/dynamo/entities/control/membership-entity.ts
|
|
292
|
-
import { Entity as Entity2 } from "electrodb";
|
|
293
|
-
var MembershipEntity = new Entity2({
|
|
294
|
-
model: {
|
|
295
|
-
entity: "membership",
|
|
296
|
-
service: "control",
|
|
297
|
-
version: "01"
|
|
298
|
-
},
|
|
299
|
-
attributes: {
|
|
300
|
-
/** Sort key sentinel. Always "CURRENT". */
|
|
301
|
-
sk: {
|
|
302
|
-
type: "string",
|
|
303
|
-
required: true,
|
|
304
|
-
default: "CURRENT"
|
|
305
|
-
},
|
|
306
|
-
/** Tenant in which the user has membership (required). */
|
|
307
|
-
tenantId: {
|
|
308
|
-
type: "string",
|
|
309
|
-
required: true
|
|
310
|
-
},
|
|
311
|
-
/** FHIR Resource.id; membership id. */
|
|
312
|
-
id: {
|
|
313
|
-
type: "string",
|
|
314
|
-
required: true
|
|
315
|
-
},
|
|
316
|
-
/** Full Membership resource serialized as JSON string. */
|
|
317
|
-
resource: {
|
|
318
|
-
type: "string",
|
|
319
|
-
required: true
|
|
320
|
-
},
|
|
321
|
-
/**
|
|
322
|
-
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
323
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
324
|
-
*/
|
|
325
|
-
summary: {
|
|
326
|
-
type: "string",
|
|
327
|
-
required: true
|
|
328
|
-
},
|
|
329
|
-
/** Version id (e.g. ULID). */
|
|
330
|
-
vid: {
|
|
331
|
-
type: "string",
|
|
332
|
-
required: true
|
|
333
|
-
},
|
|
334
|
-
lastUpdated: {
|
|
335
|
-
type: "string",
|
|
336
|
-
required: true
|
|
337
|
-
},
|
|
338
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
339
|
-
deleted: {
|
|
340
|
-
type: "boolean",
|
|
341
|
-
required: false
|
|
342
|
-
},
|
|
343
|
-
bundleId: {
|
|
344
|
-
type: "string",
|
|
345
|
-
required: false
|
|
346
|
-
},
|
|
347
|
-
msgId: {
|
|
348
|
-
type: "string",
|
|
349
|
-
required: false
|
|
350
|
-
}
|
|
351
|
-
},
|
|
352
|
-
indexes: {
|
|
353
|
-
/** Base table: PK = TID#<tenantId>#MEMBERSHIP#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
354
|
-
record: {
|
|
355
|
-
pk: {
|
|
356
|
-
field: "PK",
|
|
357
|
-
composite: ["tenantId", "id"],
|
|
358
|
-
template: "TID#${tenantId}#MEMBERSHIP#ID#${id}"
|
|
359
|
-
},
|
|
360
|
-
sk: {
|
|
361
|
-
field: "SK",
|
|
362
|
-
composite: ["sk"],
|
|
363
|
-
template: "${sk}"
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
/**
|
|
367
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Memberships for a tenant across the
|
|
368
|
-
* four shards. Membership is tenant-scoped only, so `WID#-` is a sentinel.
|
|
369
|
-
* SK is `<ISO-8601 lastUpdated>#<id>` (control-plane unlabeled per DR-004).
|
|
370
|
-
* `casing: "none"` on the SK preserves ISO-8601 `T`/`Z`.
|
|
371
|
-
*/
|
|
372
|
-
gsi1: {
|
|
373
|
-
index: "GSI1",
|
|
374
|
-
pk: {
|
|
375
|
-
field: "GSI1PK",
|
|
376
|
-
composite: ["tenantId", "gsi1Shard"],
|
|
377
|
-
template: "TID#${tenantId}#WID#-#RT#Membership#SHARD#${gsi1Shard}"
|
|
378
|
-
},
|
|
379
|
-
sk: {
|
|
380
|
-
field: "GSI1SK",
|
|
381
|
-
casing: "none",
|
|
382
|
-
composite: ["lastUpdated", "id"],
|
|
383
|
-
template: "${lastUpdated}#${id}"
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// src/data/dynamo/entities/control/role-entity.ts
|
|
390
|
-
import { Entity as Entity3 } from "electrodb";
|
|
391
|
-
var RoleEntity = new Entity3({
|
|
392
|
-
model: {
|
|
393
|
-
entity: "role",
|
|
394
|
-
service: "control",
|
|
395
|
-
version: "01"
|
|
396
|
-
},
|
|
397
|
-
attributes: {
|
|
398
|
-
/** Sort key sentinel. Always "CURRENT". */
|
|
399
|
-
sk: {
|
|
400
|
-
type: "string",
|
|
401
|
-
required: true,
|
|
402
|
-
default: "CURRENT"
|
|
403
|
-
},
|
|
404
|
-
/** FHIR Resource.id; role id. */
|
|
405
|
-
id: {
|
|
406
|
-
type: "string",
|
|
407
|
-
required: true
|
|
408
|
-
},
|
|
409
|
-
/** Full Role resource serialized as JSON string. */
|
|
410
|
-
resource: {
|
|
411
|
-
type: "string",
|
|
412
|
-
required: true
|
|
413
|
-
},
|
|
414
|
-
/**
|
|
415
|
-
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
416
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
417
|
-
*/
|
|
418
|
-
summary: {
|
|
419
|
-
type: "string",
|
|
420
|
-
required: true
|
|
421
|
-
},
|
|
422
|
-
/** Version id (e.g. ULID). */
|
|
423
|
-
vid: {
|
|
424
|
-
type: "string",
|
|
425
|
-
required: true
|
|
426
|
-
},
|
|
427
|
-
lastUpdated: {
|
|
428
|
-
type: "string",
|
|
429
|
-
required: true
|
|
430
|
-
},
|
|
431
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
432
|
-
deleted: {
|
|
433
|
-
type: "boolean",
|
|
434
|
-
required: false
|
|
435
|
-
},
|
|
436
|
-
bundleId: {
|
|
437
|
-
type: "string",
|
|
438
|
-
required: false
|
|
439
|
-
},
|
|
440
|
-
msgId: {
|
|
441
|
-
type: "string",
|
|
442
|
-
required: false
|
|
443
|
-
}
|
|
444
|
-
},
|
|
445
|
-
indexes: {
|
|
446
|
-
/** Base table: PK = ROLE#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
447
|
-
record: {
|
|
448
|
-
pk: {
|
|
449
|
-
field: "PK",
|
|
450
|
-
composite: ["id"],
|
|
451
|
-
template: "ROLE#ID#${id}"
|
|
452
|
-
},
|
|
453
|
-
sk: {
|
|
454
|
-
field: "SK",
|
|
455
|
-
composite: ["sk"],
|
|
456
|
-
template: "${sk}"
|
|
457
|
-
}
|
|
458
|
-
},
|
|
459
|
-
/**
|
|
460
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Roles across the four shards.
|
|
461
|
-
* Non-tenant-isolated, so `TID#-#WID#-` sentinels precede `RT#Role#SHARD#<n>`.
|
|
462
|
-
* SK is `<ISO-8601 lastUpdated>#<id>` (control-plane unlabeled per DR-004).
|
|
463
|
-
* `casing: "none"` on the SK preserves ISO-8601 `T`/`Z`.
|
|
464
|
-
*/
|
|
465
|
-
gsi1: {
|
|
466
|
-
index: "GSI1",
|
|
467
|
-
pk: {
|
|
468
|
-
field: "GSI1PK",
|
|
469
|
-
composite: ["gsi1Shard"],
|
|
470
|
-
template: "TID#-#WID#-#RT#Role#SHARD#${gsi1Shard}"
|
|
471
|
-
},
|
|
472
|
-
sk: {
|
|
473
|
-
field: "GSI1SK",
|
|
474
|
-
casing: "none",
|
|
475
|
-
composite: ["lastUpdated", "id"],
|
|
476
|
-
template: "${lastUpdated}#${id}"
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
// src/data/dynamo/entities/control/roleassignment-entity.ts
|
|
483
|
-
import { Entity as Entity4 } from "electrodb";
|
|
484
|
-
var RoleAssignmentEntity = new Entity4({
|
|
485
|
-
model: {
|
|
486
|
-
entity: "roleassignment",
|
|
487
|
-
service: "control",
|
|
488
|
-
version: "01"
|
|
489
|
-
},
|
|
490
|
-
attributes: {
|
|
491
|
-
/** Sort key sentinel. Always "CURRENT". */
|
|
492
|
-
sk: {
|
|
493
|
-
type: "string",
|
|
494
|
-
required: true,
|
|
495
|
-
default: "CURRENT"
|
|
496
|
-
},
|
|
497
|
-
/** Tenant in which the role assignment applies (required). */
|
|
498
|
-
tenantId: {
|
|
499
|
-
type: "string",
|
|
500
|
-
required: true
|
|
501
|
-
},
|
|
502
|
-
/** FHIR Resource.id; role assignment id. */
|
|
503
|
-
id: {
|
|
504
|
-
type: "string",
|
|
505
|
-
required: true
|
|
506
|
-
},
|
|
507
|
-
/** Full RoleAssignment resource serialized as JSON string. */
|
|
508
|
-
resource: {
|
|
509
|
-
type: "string",
|
|
510
|
-
required: true
|
|
511
|
-
},
|
|
512
|
-
/**
|
|
513
|
-
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
514
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
515
|
-
*/
|
|
516
|
-
summary: {
|
|
517
|
-
type: "string",
|
|
518
|
-
required: true
|
|
519
|
-
},
|
|
520
|
-
/** Version id (e.g. ULID). */
|
|
521
|
-
vid: {
|
|
522
|
-
type: "string",
|
|
523
|
-
required: true
|
|
524
|
-
},
|
|
525
|
-
lastUpdated: {
|
|
526
|
-
type: "string",
|
|
527
|
-
required: true
|
|
528
|
-
},
|
|
529
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
530
|
-
deleted: {
|
|
531
|
-
type: "boolean",
|
|
532
|
-
required: false
|
|
533
|
-
},
|
|
534
|
-
bundleId: {
|
|
535
|
-
type: "string",
|
|
536
|
-
required: false
|
|
537
|
-
},
|
|
538
|
-
msgId: {
|
|
539
|
-
type: "string",
|
|
540
|
-
required: false
|
|
541
|
-
}
|
|
542
|
-
},
|
|
543
|
-
indexes: {
|
|
544
|
-
/** Base table: PK = TID#<tenantId>#ROLEASSIGNMENT#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
545
|
-
record: {
|
|
546
|
-
pk: {
|
|
547
|
-
field: "PK",
|
|
548
|
-
composite: ["tenantId", "id"],
|
|
549
|
-
template: "TID#${tenantId}#ROLEASSIGNMENT#ID#${id}"
|
|
550
|
-
},
|
|
551
|
-
sk: {
|
|
552
|
-
field: "SK",
|
|
553
|
-
composite: ["sk"],
|
|
554
|
-
template: "${sk}"
|
|
555
|
-
}
|
|
556
|
-
},
|
|
557
|
-
/**
|
|
558
|
-
* GSI1 — Unified Sharded List per ADR-011: list all RoleAssignments for a tenant across the
|
|
559
|
-
* four shards. Tenant-scoped only, so `WID#-` is a sentinel.
|
|
560
|
-
* SK is `<ISO-8601 lastUpdated>#<id>` (control-plane unlabeled per DR-004).
|
|
561
|
-
* `casing: "none"` on the SK preserves ISO-8601 `T`/`Z`.
|
|
562
|
-
*/
|
|
563
|
-
gsi1: {
|
|
564
|
-
index: "GSI1",
|
|
565
|
-
pk: {
|
|
566
|
-
field: "GSI1PK",
|
|
567
|
-
composite: ["tenantId", "gsi1Shard"],
|
|
568
|
-
template: "TID#${tenantId}#WID#-#RT#RoleAssignment#SHARD#${gsi1Shard}"
|
|
569
|
-
},
|
|
570
|
-
sk: {
|
|
571
|
-
field: "GSI1SK",
|
|
572
|
-
casing: "none",
|
|
573
|
-
composite: ["lastUpdated", "id"],
|
|
574
|
-
template: "${lastUpdated}#${id}"
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
// src/data/dynamo/entities/control/tenant-entity.ts
|
|
581
|
-
import { Entity as Entity5 } from "electrodb";
|
|
582
|
-
var TenantEntity = new Entity5({
|
|
583
|
-
model: {
|
|
584
|
-
entity: "tenant",
|
|
585
|
-
service: "control",
|
|
586
|
-
version: "01"
|
|
587
|
-
},
|
|
588
|
-
attributes: {
|
|
589
|
-
/** Sort key sentinel. Always "CURRENT". */
|
|
590
|
-
sk: {
|
|
591
|
-
type: "string",
|
|
592
|
-
required: true,
|
|
593
|
-
default: "CURRENT"
|
|
594
|
-
},
|
|
595
|
-
/** The tenant's own id (= resource id). Drives the partition key. */
|
|
596
|
-
tenantId: {
|
|
597
|
-
type: "string",
|
|
598
|
-
required: true
|
|
599
|
-
},
|
|
600
|
-
/** FHIR Resource.id; logical id in URL. Equals tenantId. */
|
|
601
|
-
id: {
|
|
602
|
-
type: "string",
|
|
603
|
-
required: true
|
|
604
|
-
},
|
|
605
|
-
/** Full Tenant resource serialized as JSON string. */
|
|
606
|
-
resource: {
|
|
607
|
-
type: "string",
|
|
608
|
-
required: true
|
|
609
|
-
},
|
|
610
|
-
/**
|
|
611
|
-
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
612
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
613
|
-
*/
|
|
614
|
-
summary: {
|
|
615
|
-
type: "string",
|
|
616
|
-
required: true
|
|
617
|
-
},
|
|
618
|
-
/** Version id (e.g. ULID). */
|
|
619
|
-
vid: {
|
|
620
|
-
type: "string",
|
|
621
|
-
required: true
|
|
622
|
-
},
|
|
623
|
-
lastUpdated: {
|
|
624
|
-
type: "string",
|
|
625
|
-
required: true
|
|
626
|
-
},
|
|
627
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
628
|
-
deleted: {
|
|
629
|
-
type: "boolean",
|
|
630
|
-
required: false
|
|
631
|
-
},
|
|
632
|
-
bundleId: {
|
|
633
|
-
type: "string",
|
|
634
|
-
required: false
|
|
635
|
-
},
|
|
636
|
-
msgId: {
|
|
637
|
-
type: "string",
|
|
638
|
-
required: false
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
indexes: {
|
|
642
|
-
/** Base table: PK = TENANT#ID#<tenantId>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
643
|
-
record: {
|
|
644
|
-
pk: {
|
|
645
|
-
field: "PK",
|
|
646
|
-
composite: ["tenantId"],
|
|
647
|
-
template: "TENANT#ID#${tenantId}"
|
|
648
|
-
},
|
|
649
|
-
sk: {
|
|
650
|
-
field: "SK",
|
|
651
|
-
composite: ["sk"],
|
|
652
|
-
template: "${sk}"
|
|
653
|
-
}
|
|
654
|
-
},
|
|
655
|
-
/**
|
|
656
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Tenants across the four shards.
|
|
657
|
-
* Tenant lives at the platform tier (no parent tenant or workspace), so `TID#-#WID#-`
|
|
658
|
-
* sentinels precede `RT#Tenant#SHARD#<n>`. SK is `<ISO-8601 lastUpdated>#<id>` (control-plane
|
|
659
|
-
* unlabeled per DR-004). `casing: "none"` on the SK preserves ISO-8601 `T`/`Z`.
|
|
660
|
-
*/
|
|
661
|
-
gsi1: {
|
|
662
|
-
index: "GSI1",
|
|
663
|
-
pk: {
|
|
664
|
-
field: "GSI1PK",
|
|
665
|
-
composite: ["gsi1Shard"],
|
|
666
|
-
template: "TID#-#WID#-#RT#Tenant#SHARD#${gsi1Shard}"
|
|
667
|
-
},
|
|
668
|
-
sk: {
|
|
669
|
-
field: "GSI1SK",
|
|
670
|
-
casing: "none",
|
|
671
|
-
composite: ["lastUpdated", "id"],
|
|
672
|
-
template: "${lastUpdated}#${id}"
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
// src/data/dynamo/entities/control/user-entity.ts
|
|
679
|
-
import { Entity as Entity6 } from "electrodb";
|
|
680
|
-
var UserEntity = new Entity6({
|
|
681
|
-
model: {
|
|
682
|
-
entity: "user",
|
|
683
|
-
service: "control",
|
|
684
|
-
version: "01"
|
|
685
|
-
},
|
|
686
|
-
attributes: {
|
|
687
|
-
/** Sort key sentinel. Always "CURRENT". */
|
|
688
|
-
sk: {
|
|
689
|
-
type: "string",
|
|
690
|
-
required: true,
|
|
691
|
-
default: "CURRENT"
|
|
692
|
-
},
|
|
693
|
-
/** FHIR Resource.id; platform user id (ohi_uid). */
|
|
694
|
-
id: {
|
|
695
|
-
type: "string",
|
|
696
|
-
required: true
|
|
697
|
-
},
|
|
698
|
-
/** Full User resource serialized as JSON string. */
|
|
699
|
-
resource: {
|
|
700
|
-
type: "string",
|
|
701
|
-
required: true
|
|
702
|
-
},
|
|
703
|
-
/**
|
|
704
|
-
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
705
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
706
|
-
*/
|
|
707
|
-
summary: {
|
|
708
|
-
type: "string",
|
|
709
|
-
required: true
|
|
710
|
-
},
|
|
711
|
-
/**
|
|
712
|
-
* Immutable Cognito-issued `sub` claim. Drives GSI2 (sub-lookup). Optional until the
|
|
713
|
-
* Post Confirmation Lambda (#770) lands; required thereafter.
|
|
714
|
-
*/
|
|
715
|
-
cognitoSub: {
|
|
716
|
-
type: "string",
|
|
717
|
-
required: false
|
|
718
|
-
},
|
|
719
|
-
/** Version id (e.g. ULID). */
|
|
720
|
-
vid: {
|
|
721
|
-
type: "string",
|
|
722
|
-
required: true
|
|
723
|
-
},
|
|
724
|
-
lastUpdated: {
|
|
725
|
-
type: "string",
|
|
726
|
-
required: true
|
|
727
|
-
},
|
|
728
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
729
|
-
deleted: {
|
|
730
|
-
type: "boolean",
|
|
731
|
-
required: false
|
|
732
|
-
},
|
|
733
|
-
bundleId: {
|
|
734
|
-
type: "string",
|
|
735
|
-
required: false
|
|
736
|
-
},
|
|
737
|
-
msgId: {
|
|
738
|
-
type: "string",
|
|
739
|
-
required: false
|
|
740
|
-
}
|
|
741
|
-
},
|
|
742
|
-
indexes: {
|
|
743
|
-
/** Base table: PK = USER#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
744
|
-
record: {
|
|
745
|
-
pk: {
|
|
746
|
-
field: "PK",
|
|
747
|
-
composite: ["id"],
|
|
748
|
-
template: "USER#ID#${id}"
|
|
749
|
-
},
|
|
750
|
-
sk: {
|
|
751
|
-
field: "SK",
|
|
752
|
-
composite: ["sk"],
|
|
753
|
-
template: "${sk}"
|
|
754
|
-
}
|
|
755
|
-
},
|
|
756
|
-
/**
|
|
757
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Users across the four shards.
|
|
758
|
-
* Non-tenant-isolated, so `TID#-#WID#-` sentinels precede `RT#User#SHARD#<n>`.
|
|
759
|
-
* SK is `<ISO-8601 lastUpdated>#<id>` (control-plane unlabeled per DR-004).
|
|
760
|
-
* `casing: "none"` on the SK preserves ISO-8601 `T`/`Z` characters.
|
|
761
|
-
*/
|
|
762
|
-
gsi1: {
|
|
763
|
-
index: "GSI1",
|
|
764
|
-
pk: {
|
|
765
|
-
field: "GSI1PK",
|
|
766
|
-
composite: ["gsi1Shard"],
|
|
767
|
-
template: "TID#-#WID#-#RT#User#SHARD#${gsi1Shard}"
|
|
768
|
-
},
|
|
769
|
-
sk: {
|
|
770
|
-
field: "GSI1SK",
|
|
771
|
-
casing: "none",
|
|
772
|
-
composite: ["lastUpdated", "id"],
|
|
773
|
-
template: "${lastUpdated}#${id}"
|
|
774
|
-
}
|
|
775
|
-
},
|
|
776
|
-
/**
|
|
777
|
-
* GSI2 — Cognito sub-lookup per ADR-011: resolves the UserEntity from a Cognito `sub` claim.
|
|
778
|
-
* `condition` skips the index when `cognitoSub` is missing so legacy items without a sub are
|
|
779
|
-
* not indexed.
|
|
780
|
-
*/
|
|
781
|
-
gsi2: {
|
|
782
|
-
index: "GSI2",
|
|
783
|
-
condition: (attrs) => typeof attrs.cognitoSub === "string" && attrs.cognitoSub.length > 0,
|
|
784
|
-
pk: {
|
|
785
|
-
field: "GSI2PK",
|
|
786
|
-
casing: "none",
|
|
787
|
-
composite: ["cognitoSub"],
|
|
788
|
-
template: "USER#SUB#${cognitoSub}"
|
|
789
|
-
},
|
|
790
|
-
sk: {
|
|
791
|
-
field: "GSI2SK",
|
|
792
|
-
casing: "none",
|
|
793
|
-
composite: [],
|
|
794
|
-
template: "CURRENT"
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
});
|
|
799
|
-
|
|
800
|
-
// src/data/dynamo/entities/control/workspace-entity.ts
|
|
801
|
-
import { Entity as Entity7 } from "electrodb";
|
|
802
|
-
var WorkspaceEntity = new Entity7({
|
|
803
|
-
model: {
|
|
804
|
-
entity: "workspace",
|
|
805
|
-
service: "control",
|
|
806
|
-
version: "01"
|
|
807
|
-
},
|
|
808
|
-
attributes: {
|
|
809
|
-
/** Sort key sentinel. Always "CURRENT". */
|
|
810
|
-
sk: {
|
|
811
|
-
type: "string",
|
|
812
|
-
required: true,
|
|
813
|
-
default: "CURRENT"
|
|
814
|
-
},
|
|
815
|
-
/** Tenant that contains this workspace (required). */
|
|
816
|
-
tenantId: {
|
|
817
|
-
type: "string",
|
|
818
|
-
required: true
|
|
819
|
-
},
|
|
820
|
-
/** FHIR Resource.id; logical id in URL. */
|
|
821
|
-
id: {
|
|
822
|
-
type: "string",
|
|
823
|
-
required: true
|
|
824
|
-
},
|
|
825
|
-
/** Full Workspace resource serialized as JSON string. */
|
|
826
|
-
resource: {
|
|
827
|
-
type: "string",
|
|
828
|
-
required: true
|
|
829
|
-
},
|
|
830
|
-
/**
|
|
831
|
-
* Summary projection (key display fields as JSON string: id, displayName, status).
|
|
832
|
-
* Populated on every write via extractSummary(resource); GSI1 INCLUDE surfaces it on lists.
|
|
833
|
-
*/
|
|
834
|
-
summary: {
|
|
835
|
-
type: "string",
|
|
836
|
-
required: true
|
|
837
|
-
},
|
|
838
|
-
/** Version id (e.g. ULID). */
|
|
839
|
-
vid: {
|
|
840
|
-
type: "string",
|
|
841
|
-
required: true
|
|
842
|
-
},
|
|
843
|
-
lastUpdated: {
|
|
844
|
-
type: "string",
|
|
845
|
-
required: true
|
|
846
|
-
},
|
|
847
|
-
gsi1Shard: gsi1ShardAttribute,
|
|
848
|
-
deleted: {
|
|
849
|
-
type: "boolean",
|
|
850
|
-
required: false
|
|
851
|
-
},
|
|
852
|
-
bundleId: {
|
|
853
|
-
type: "string",
|
|
854
|
-
required: false
|
|
855
|
-
},
|
|
856
|
-
msgId: {
|
|
857
|
-
type: "string",
|
|
858
|
-
required: false
|
|
859
|
-
}
|
|
860
|
-
},
|
|
861
|
-
indexes: {
|
|
862
|
-
/** Base table: PK = TID#<tenantId>#WORKSPACE#ID#<id>, SK = CURRENT. Do not supply PK or SK from outside. */
|
|
863
|
-
record: {
|
|
864
|
-
pk: {
|
|
865
|
-
field: "PK",
|
|
866
|
-
composite: ["tenantId", "id"],
|
|
867
|
-
template: "TID#${tenantId}#WORKSPACE#ID#${id}"
|
|
868
|
-
},
|
|
869
|
-
sk: {
|
|
870
|
-
field: "SK",
|
|
871
|
-
composite: ["sk"],
|
|
872
|
-
template: "${sk}"
|
|
873
|
-
}
|
|
874
|
-
},
|
|
875
|
-
/**
|
|
876
|
-
* GSI1 — Unified Sharded List per ADR-011: list all Workspaces for a tenant across the
|
|
877
|
-
* four shards. Workspace is itself the workspace identity, so `WID#-` is a sentinel.
|
|
878
|
-
* SK is `<ISO-8601 lastUpdated>#<id>` (control-plane unlabeled per DR-004).
|
|
879
|
-
* `casing: "none"` on the SK preserves ISO-8601 `T`/`Z`.
|
|
880
|
-
*/
|
|
881
|
-
gsi1: {
|
|
882
|
-
index: "GSI1",
|
|
883
|
-
pk: {
|
|
884
|
-
field: "GSI1PK",
|
|
885
|
-
composite: ["tenantId", "gsi1Shard"],
|
|
886
|
-
template: "TID#${tenantId}#WID#-#RT#Workspace#SHARD#${gsi1Shard}"
|
|
887
|
-
},
|
|
888
|
-
sk: {
|
|
889
|
-
field: "GSI1SK",
|
|
890
|
-
casing: "none",
|
|
891
|
-
composite: ["lastUpdated", "id"],
|
|
892
|
-
template: "${lastUpdated}#${id}"
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
|
|
898
|
-
// src/data/dynamo/dynamo-control-service.ts
|
|
899
|
-
var controlPlaneEntities = {
|
|
900
|
-
configuration: ConfigurationEntity,
|
|
901
|
-
membership: MembershipEntity,
|
|
902
|
-
role: RoleEntity,
|
|
903
|
-
roleAssignment: RoleAssignmentEntity,
|
|
904
|
-
tenant: TenantEntity,
|
|
905
|
-
user: UserEntity,
|
|
906
|
-
workspace: WorkspaceEntity
|
|
907
|
-
};
|
|
908
|
-
var controlPlaneService = new Service(controlPlaneEntities, {
|
|
909
|
-
table: defaultTableName,
|
|
910
|
-
client: dynamoClient
|
|
911
|
-
});
|
|
912
|
-
var DynamoControlService = {
|
|
913
|
-
entities: controlPlaneService.entities
|
|
914
|
-
};
|
|
915
|
-
function getDynamoControlService(tableName) {
|
|
916
|
-
const resolved = tableName ?? defaultTableName;
|
|
917
|
-
const service = new Service(controlPlaneEntities, {
|
|
918
|
-
table: resolved,
|
|
919
|
-
client: dynamoClient
|
|
920
|
-
});
|
|
921
|
-
return {
|
|
922
|
-
entities: service.entities
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
|
|
926
134
|
// src/data/operations/control/configuration/configuration-create-operation.ts
|
|
927
135
|
var SK = "CURRENT";
|
|
928
136
|
async function createConfigurationOperation(params) {
|
|
@@ -3579,10 +2787,10 @@ import express8 from "express";
|
|
|
3579
2787
|
import { ulid } from "ulid";
|
|
3580
2788
|
|
|
3581
2789
|
// src/data/dynamo/dynamo-data-service.ts
|
|
3582
|
-
import { Service
|
|
2790
|
+
import { Service } from "electrodb";
|
|
3583
2791
|
|
|
3584
2792
|
// src/data/dynamo/entities/data-entity-common.ts
|
|
3585
|
-
import { Entity
|
|
2793
|
+
import { Entity } from "electrodb";
|
|
3586
2794
|
var dataEntityAttributes = {
|
|
3587
2795
|
/** Sort key. "CURRENT" for current version; version history in S3. */
|
|
3588
2796
|
sk: {
|
|
@@ -3678,7 +2886,7 @@ var dataEntityAttributes = {
|
|
|
3678
2886
|
}
|
|
3679
2887
|
};
|
|
3680
2888
|
function createDataEntity(entity, resourceTypeLabel) {
|
|
3681
|
-
return new
|
|
2889
|
+
return new Entity({
|
|
3682
2890
|
model: {
|
|
3683
2891
|
entity,
|
|
3684
2892
|
service: "data",
|
|
@@ -4592,7 +3800,7 @@ var dataPlaneEntities = {
|
|
|
4592
3800
|
visionprescription: VisionPrescriptionEntity,
|
|
4593
3801
|
verificationresult: VerificationResultEntity
|
|
4594
3802
|
};
|
|
4595
|
-
var dataPlaneService = new
|
|
3803
|
+
var dataPlaneService = new Service(dataPlaneEntities, {
|
|
4596
3804
|
table: defaultTableName,
|
|
4597
3805
|
client: dynamoClient
|
|
4598
3806
|
});
|
|
@@ -4601,7 +3809,7 @@ var DynamoDataService = {
|
|
|
4601
3809
|
};
|
|
4602
3810
|
function getDynamoDataService(tableName) {
|
|
4603
3811
|
const resolved = tableName ?? defaultTableName;
|
|
4604
|
-
const service = new
|
|
3812
|
+
const service = new Service(dataPlaneEntities, {
|
|
4605
3813
|
table: resolved,
|
|
4606
3814
|
client: dynamoClient
|
|
4607
3815
|
});
|