@openhi/constructs 0.0.178 → 0.0.180
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-Z4PZSLYY.mjs → chunk-3M4QTQH6.mjs} +2 -2
- package/lib/{chunk-JUSVETWK.mjs → chunk-4LQR32D2.mjs} +38 -40
- package/lib/{chunk-JUSVETWK.mjs.map → chunk-4LQR32D2.mjs.map} +1 -1
- package/lib/{chunk-XNUCKVSE.mjs → chunk-7GMTHOYF.mjs} +2 -2
- package/lib/{chunk-E2OWEBBH.mjs → chunk-DIVYB6GD.mjs} +18 -4
- package/lib/chunk-DIVYB6GD.mjs.map +1 -0
- package/lib/chunk-F2LY4TEI.mjs +272 -0
- package/lib/chunk-F2LY4TEI.mjs.map +1 -0
- package/lib/{chunk-GG2WD6TA.mjs → chunk-JJ3AQ6G5.mjs} +9 -3
- package/lib/{chunk-GG2WD6TA.mjs.map → chunk-JJ3AQ6G5.mjs.map} +1 -1
- package/lib/{chunk-EBB4RNUG.mjs → chunk-PIQISEGW.mjs} +2 -2
- package/lib/{chunk-FDBBTNCI.mjs → chunk-Q4KQD2NB.mjs} +117 -5
- package/lib/chunk-Q4KQD2NB.mjs.map +1 -0
- package/lib/{chunk-Y4RGUAM2.mjs → chunk-V6KLFEHC.mjs} +105 -34
- package/lib/chunk-V6KLFEHC.mjs.map +1 -0
- package/lib/chunk-VQY57NOV.mjs +60 -0
- package/lib/chunk-VQY57NOV.mjs.map +1 -0
- package/lib/counter-maintenance.handler.mjs +4 -4
- package/lib/counter-reconciliation.handler.js +2 -2
- package/lib/counter-reconciliation.handler.js.map +1 -1
- package/lib/counter-reconciliation.handler.mjs +9 -267
- package/lib/counter-reconciliation.handler.mjs.map +1 -1
- package/lib/index.d.mts +117 -2
- package/lib/index.d.ts +117 -2
- package/lib/index.js +6454 -6243
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +106 -4
- package/lib/index.mjs.map +1 -1
- package/lib/pre-token-generation.handler.js +28 -19
- package/lib/pre-token-generation.handler.js.map +1 -1
- package/lib/pre-token-generation.handler.mjs +4 -5
- package/lib/pre-token-generation.handler.mjs.map +1 -1
- package/lib/provision-default-workspace.handler.js +22 -19
- package/lib/provision-default-workspace.handler.js.map +1 -1
- package/lib/provision-default-workspace.handler.mjs +3 -4
- package/lib/provision-default-workspace.handler.mjs.map +1 -1
- package/lib/rest-api-lambda.handler.js +367 -208
- package/lib/rest-api-lambda.handler.js.map +1 -1
- package/lib/rest-api-lambda.handler.mjs +210 -165
- package/lib/rest-api-lambda.handler.mjs.map +1 -1
- package/lib/seed-demo-data.handler.d.mts +19 -0
- package/lib/seed-demo-data.handler.d.ts +19 -0
- package/lib/seed-demo-data.handler.js +805 -159
- package/lib/seed-demo-data.handler.js.map +1 -1
- package/lib/seed-demo-data.handler.mjs +8 -4
- package/package.json +1 -1
- package/lib/chunk-6HGSR3TG.mjs +0 -123
- package/lib/chunk-6HGSR3TG.mjs.map +0 -1
- package/lib/chunk-E2OWEBBH.mjs.map +0 -1
- package/lib/chunk-FDBBTNCI.mjs.map +0 -1
- package/lib/chunk-Y4RGUAM2.mjs.map +0 -1
- /package/lib/{chunk-Z4PZSLYY.mjs.map → chunk-3M4QTQH6.mjs.map} +0 -0
- /package/lib/{chunk-XNUCKVSE.mjs.map → chunk-7GMTHOYF.mjs.map} +0 -0
- /package/lib/{chunk-EBB4RNUG.mjs.map → chunk-PIQISEGW.mjs.map} +0 -0
|
@@ -8,15 +8,19 @@ import {
|
|
|
8
8
|
productionCognitoProvisioner,
|
|
9
9
|
runSeedDemoData,
|
|
10
10
|
seedDemoGraph
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-DIVYB6GD.mjs";
|
|
12
|
+
import "./chunk-F2LY4TEI.mjs";
|
|
13
|
+
import "./chunk-RQKJNMX5.mjs";
|
|
14
|
+
import "./chunk-7GMTHOYF.mjs";
|
|
15
|
+
import "./chunk-4LQR32D2.mjs";
|
|
16
|
+
import "./chunk-PIQISEGW.mjs";
|
|
17
|
+
import "./chunk-3M4QTQH6.mjs";
|
|
14
18
|
import "./chunk-BUAYVN3C.mjs";
|
|
15
19
|
import "./chunk-5S6VFBLT.mjs";
|
|
16
20
|
import "./chunk-I6LUPJUY.mjs";
|
|
17
21
|
import "./chunk-QJDHVMKT.mjs";
|
|
18
22
|
import "./chunk-6BB4CRSS.mjs";
|
|
19
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-Q4KQD2NB.mjs";
|
|
20
24
|
import "./chunk-APVVG7BO.mjs";
|
|
21
25
|
import "./chunk-FYHBHHWK.mjs";
|
|
22
26
|
import "./chunk-EUIP2U5F.mjs";
|
package/package.json
CHANGED
package/lib/chunk-6HGSR3TG.mjs
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
batchGetWithRetry,
|
|
3
|
-
dispatchListMode
|
|
4
|
-
} from "./chunk-FDBBTNCI.mjs";
|
|
5
|
-
import {
|
|
6
|
-
SHARD_COUNT,
|
|
7
|
-
getDynamoControlService
|
|
8
|
-
} from "./chunk-EUIP2U5F.mjs";
|
|
9
|
-
|
|
10
|
-
// src/data/operations/control/user/user-list-operation.ts
|
|
11
|
-
var SK = "CURRENT";
|
|
12
|
-
function counterValue(value) {
|
|
13
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
14
|
-
}
|
|
15
|
-
async function listUsersOperation(params) {
|
|
16
|
-
const { tableName, mode = "full" } = params;
|
|
17
|
-
const service = getDynamoControlService(tableName);
|
|
18
|
-
const shardResults = await Promise.all(
|
|
19
|
-
Array.from(
|
|
20
|
-
{ length: SHARD_COUNT },
|
|
21
|
-
(_, shard) => service.entities.user.query.gsi1({ gsi1Shard: String(shard) }).go()
|
|
22
|
-
)
|
|
23
|
-
);
|
|
24
|
-
return dispatchListMode(mode, shardResults, {
|
|
25
|
-
hydrate: (orderedIds) => batchGetWithRetry(
|
|
26
|
-
service.entities.user,
|
|
27
|
-
orderedIds.map((id) => ({ id, sk: SK }))
|
|
28
|
-
),
|
|
29
|
-
getId: (item) => item.id,
|
|
30
|
-
// FULL mode (admin list default): read the ADR-028 counters off the
|
|
31
|
-
// canonical record hydrated by BatchGet and expose them as
|
|
32
|
-
// `resource.counts`. Missing counters render as 0.
|
|
33
|
-
buildEntry: (id, item) => ({
|
|
34
|
-
id,
|
|
35
|
-
resource: {
|
|
36
|
-
resourceType: "User",
|
|
37
|
-
id,
|
|
38
|
-
...JSON.parse(item.resource),
|
|
39
|
-
counts: {
|
|
40
|
-
tenantsForUser: counterValue(item.tenantsForUser),
|
|
41
|
-
workspacesForUser: counterValue(item.workspacesForUser)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}),
|
|
45
|
-
// SUMMARY mode reads only the GSI1 `summary` projection (no
|
|
46
|
-
// counters); surface zeros so the shape stays uniform.
|
|
47
|
-
buildSummaryEntry: (id, parsed) => ({
|
|
48
|
-
id,
|
|
49
|
-
resource: {
|
|
50
|
-
resourceType: "User",
|
|
51
|
-
id,
|
|
52
|
-
...parsed,
|
|
53
|
-
counts: { tenantsForUser: 0, workspacesForUser: 0 }
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/data/operations/control/membership/membership-list-by-user-operation.ts
|
|
60
|
-
function buildSkPrefix(mode, tenantId) {
|
|
61
|
-
switch (mode) {
|
|
62
|
-
case "tenant":
|
|
63
|
-
return "MEMBERSHIP#TENANT#";
|
|
64
|
-
case "workspace":
|
|
65
|
-
return "MEMBERSHIP#WORKSPACE#";
|
|
66
|
-
case "workspaceInTenant":
|
|
67
|
-
return `MEMBERSHIP#WORKSPACE#TID#${tenantId}#`;
|
|
68
|
-
case "all":
|
|
69
|
-
default:
|
|
70
|
-
return "MEMBERSHIP#";
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
async function membershipListByUserOperation(params) {
|
|
74
|
-
const {
|
|
75
|
-
userId,
|
|
76
|
-
mode = "all",
|
|
77
|
-
tenantId,
|
|
78
|
-
cursor = null,
|
|
79
|
-
limit,
|
|
80
|
-
order,
|
|
81
|
-
tableName
|
|
82
|
-
} = params;
|
|
83
|
-
if (mode === "workspaceInTenant" && !tenantId) {
|
|
84
|
-
throw new Error(
|
|
85
|
-
'membershipListByUserOperation: tenantId is required when mode === "workspaceInTenant"'
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
const service = getDynamoControlService(tableName);
|
|
89
|
-
const skPrefix = buildSkPrefix(mode, tenantId);
|
|
90
|
-
const goOptions = {
|
|
91
|
-
cursor
|
|
92
|
-
};
|
|
93
|
-
if (limit !== void 0) {
|
|
94
|
-
goOptions.limit = limit;
|
|
95
|
-
}
|
|
96
|
-
if (order !== void 0) {
|
|
97
|
-
goOptions.order = order;
|
|
98
|
-
}
|
|
99
|
-
const result = await service.entities.membershipUserProjection.query.record({ userId }).begins({ sk: skPrefix }).go(goOptions);
|
|
100
|
-
const items = (result.data ?? []).map(
|
|
101
|
-
(row) => ({
|
|
102
|
-
userId: row.userId,
|
|
103
|
-
sk: row.sk,
|
|
104
|
-
tenantId: row.tenantId,
|
|
105
|
-
workspaceId: row.workspaceId,
|
|
106
|
-
membershipId: row.membershipId,
|
|
107
|
-
summary: row.summary,
|
|
108
|
-
vid: row.vid,
|
|
109
|
-
lastUpdated: row.lastUpdated,
|
|
110
|
-
denormalizedTenantName: row.denormalizedTenantName,
|
|
111
|
-
denormalizedUserName: row.denormalizedUserName,
|
|
112
|
-
denormalizedWorkspaceName: row.denormalizedWorkspaceName
|
|
113
|
-
})
|
|
114
|
-
);
|
|
115
|
-
return { items, cursor: result.cursor ?? null };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export {
|
|
119
|
-
buildSkPrefix,
|
|
120
|
-
membershipListByUserOperation,
|
|
121
|
-
listUsersOperation
|
|
122
|
-
};
|
|
123
|
-
//# sourceMappingURL=chunk-6HGSR3TG.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/data/operations/control/user/user-list-operation.ts","../src/data/operations/control/membership/membership-list-by-user-operation.ts"],"sourcesContent":["import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\nimport { SHARD_COUNT } from \"../../../dynamo/shard\";\nimport { OpenHiContext } from \"../../../openhi-context\";\nimport {\n batchGetWithRetry,\n dispatchListMode,\n type ListOperationMode,\n} from \"../../data-operations-common\";\n\nconst SK = \"CURRENT\";\n\nexport interface UserListParams {\n context: OpenHiContext;\n tableName?: string;\n /** #853: defaults to `\"full\"`. `\"summary\"` skips BatchGet, `\"count\"` returns total only. */\n mode?: ListOperationMode;\n}\n\n/**\n * ADR-028 denormalized counter shape surfaced on a User list entry's\n * `resource.counts`. Missing counters render as `0`.\n */\nexport interface UserCounts {\n tenantsForUser: number;\n workspacesForUser: number;\n}\n\nexport interface UserListResult {\n entries: Array<{\n id: string;\n resource: {\n resourceType: string;\n id: string;\n counts: UserCounts;\n [key: string]: unknown;\n };\n }>;\n total: number;\n}\n\n/** Coerce a possibly-absent counter attribute to a non-negative number (default 0). */\nfunction counterValue(value: unknown): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n}\n\n/**\n * Lists Users via GSI1 (sharded). `mode` (default `\"full\"`) selects between BatchGet hydration,\n * summary-only (parse `summary` JSON projected on GSI1), or count-only (skip both). See\n * `dispatchListMode` in data-operations-common for the canonical mode contract.\n */\nexport async function listUsersOperation(\n params: UserListParams,\n): Promise<UserListResult> {\n const { tableName, mode = \"full\" } = params;\n const service = getDynamoControlService(tableName);\n\n const shardResults = await Promise.all(\n Array.from({ length: SHARD_COUNT }, (_, shard) =>\n service.entities.user.query.gsi1({ gsi1Shard: String(shard) }).go(),\n ),\n );\n\n return dispatchListMode<\n {\n id: string;\n resource: string;\n tenantsForUser?: number;\n workspacesForUser?: number;\n },\n UserListResult[\"entries\"][number]\n >(mode, shardResults, {\n hydrate: (orderedIds) =>\n batchGetWithRetry(\n service.entities.user,\n orderedIds.map((id) => ({ id, sk: SK })),\n ) as Promise<\n Array<{\n id: string;\n resource: string;\n tenantsForUser?: number;\n workspacesForUser?: number;\n }>\n >,\n getId: (item) => item.id,\n // FULL mode (admin list default): read the ADR-028 counters off the\n // canonical record hydrated by BatchGet and expose them as\n // `resource.counts`. Missing counters render as 0.\n buildEntry: (id, item) => ({\n id,\n resource: {\n resourceType: \"User\",\n id,\n ...(JSON.parse(item.resource) as Record<string, unknown>),\n counts: {\n tenantsForUser: counterValue(item.tenantsForUser),\n workspacesForUser: counterValue(item.workspacesForUser),\n },\n },\n }),\n // SUMMARY mode reads only the GSI1 `summary` projection (no\n // counters); surface zeros so the shape stays uniform.\n buildSummaryEntry: (id, parsed) => ({\n id,\n resource: {\n resourceType: \"User\",\n id,\n ...parsed,\n counts: { tenantsForUser: 0, workspacesForUser: 0 },\n },\n }),\n });\n}\n","import { getDynamoControlService } from \"../../../dynamo/dynamo-control-service\";\n\n/**\n * Filter modes for {@link membershipListByUserOperation}.\n *\n * Maps directly to the ADR-018 sub-lane discriminator in the user-projection\n * SK (`MEMBERSHIP#TENANT#…` vs `MEMBERSHIP#WORKSPACE#…`):\n *\n * - `\"all\"` — `Query(PK = USER#ID#<userId>, SK begins_with 'MEMBERSHIP#')`.\n * Returns both lanes interleaved in raw SK order.\n * - `\"tenant\"` — `SK begins_with 'MEMBERSHIP#TENANT#'`. Pattern #3 only.\n * - `\"workspace\"` — `SK begins_with 'MEMBERSHIP#WORKSPACE#'`. Pattern #4\n * across every tenant.\n * - `\"workspaceInTenant\"` — `SK begins_with 'MEMBERSHIP#WORKSPACE#TID#<tenantId>#'`.\n * Pattern #4 narrowed to one tenant. Requires `tenantId`.\n */\nexport type MembershipListByUserMode =\n | \"all\"\n | \"tenant\"\n | \"workspace\"\n | \"workspaceInTenant\";\n\n/** Inputs accepted by {@link membershipListByUserOperation}. */\nexport interface MembershipListByUserParams {\n readonly userId: string;\n /** Filter mode — see {@link MembershipListByUserMode}. Defaults to `\"all\"`. */\n readonly mode?: MembershipListByUserMode;\n /** Required only when `mode === \"workspaceInTenant\"`. */\n readonly tenantId?: string;\n /** ElectroDB cursor from a prior page. Forwarded to `.go({ cursor })`. */\n readonly cursor?: string | null;\n /** Per-page item limit forwarded to `.go({ limit })`. */\n readonly limit?: number;\n /** Sort order forwarded to `.go({ order })`. Defaults to ElectroDB's `\"asc\"`. */\n readonly order?: \"asc\" | \"desc\";\n /** Optional table-name override; resolved via env when omitted. */\n readonly tableName?: string;\n}\n\n/** One projection-row payload as returned to a consumer. */\nexport interface MembershipUserProjectionEntry {\n readonly userId: string;\n readonly sk: string;\n readonly tenantId: string;\n readonly workspaceId?: string;\n readonly membershipId: string;\n readonly summary: string;\n readonly vid: string;\n readonly lastUpdated: string;\n readonly denormalizedTenantName?: string;\n readonly denormalizedUserName?: string;\n readonly denormalizedWorkspaceName?: string;\n}\n\n/** Page returned by {@link membershipListByUserOperation}. */\nexport interface MembershipListByUserResult {\n readonly items: Array<MembershipUserProjectionEntry>;\n /** ElectroDB cursor for the next page, or `null` when exhausted. */\n readonly cursor: string | null;\n}\n\n/**\n * Compose the SK prefix for a given filter mode. Centralizing the\n * prefix string here keeps the SK grammar (owned by\n * `membership-user-projection.ts`) the single source of truth for the\n * lane discriminators — this function reads them, it does not invent them.\n */\nexport function buildSkPrefix(\n mode: MembershipListByUserMode,\n tenantId: string | undefined,\n): string {\n switch (mode) {\n case \"tenant\":\n return \"MEMBERSHIP#TENANT#\";\n case \"workspace\":\n return \"MEMBERSHIP#WORKSPACE#\";\n case \"workspaceInTenant\":\n // Pattern-#4 SK places `<tenantId>` directly after the\n // `MEMBERSHIP#WORKSPACE#TID#` segment so a `begins_with` filter\n // narrows the workspace lane to a single tenant.\n return `MEMBERSHIP#WORKSPACE#TID#${tenantId}#`;\n case \"all\":\n default:\n return \"MEMBERSHIP#\";\n }\n}\n\n/**\n * List Memberships for a user via the ADR-018 user-partition projection\n * (no GSI hop).\n *\n * Reads `MembershipUserProjectionEntity` rows under `PK = USER#ID#<userId>`\n * with an `SK begins_with` filter selected by `mode`:\n *\n * | Mode | SK begins_with | Covers |\n * |---|---|---|\n * | `all` (default) | `MEMBERSHIP#` | patterns #3 + #4 interleaved |\n * | `tenant` | `MEMBERSHIP#TENANT#` | pattern #3 only |\n * | `workspace` | `MEMBERSHIP#WORKSPACE#` | pattern #4 only, across tenants |\n * | `workspaceInTenant` | `MEMBERSHIP#WORKSPACE#TID#<tenantId>#` | pattern #4 in one tenant |\n *\n * Returns the projection rows verbatim (`summary`, `vid`, `lastUpdated`\n * plus the projection-discriminating fields) — full canonical-resource\n * hydration is opt-in for callers via\n * `MembershipEntity.get({ tenantId, id: membershipId })`. Pagination\n * mirrors ElectroDB's native `.go({ cursor })` shape; the returned\n * `cursor` is opaque to callers.\n *\n * @see ADR-018 § Access Pattern Coverage (patterns #3 and #4)\n * @see .state/adr-018-implementation-guide.md § 1 (SK grammar)\n */\nexport async function membershipListByUserOperation(\n params: MembershipListByUserParams,\n): Promise<MembershipListByUserResult> {\n const {\n userId,\n mode = \"all\",\n tenantId,\n cursor = null,\n limit,\n order,\n tableName,\n } = params;\n\n if (mode === \"workspaceInTenant\" && !tenantId) {\n throw new Error(\n 'membershipListByUserOperation: tenantId is required when mode === \"workspaceInTenant\"',\n );\n }\n\n const service = getDynamoControlService(tableName);\n const skPrefix = buildSkPrefix(mode, tenantId);\n\n const goOptions: {\n cursor?: string | null;\n limit?: number;\n order?: \"asc\" | \"desc\";\n } = {\n cursor,\n };\n if (limit !== undefined) {\n goOptions.limit = limit;\n }\n if (order !== undefined) {\n goOptions.order = order;\n }\n\n const result = await service.entities.membershipUserProjection.query\n .record({ userId })\n .begins({ sk: skPrefix })\n .go(goOptions);\n\n const items: Array<MembershipUserProjectionEntry> = (result.data ?? []).map(\n (row) => ({\n userId: row.userId,\n sk: row.sk,\n tenantId: row.tenantId,\n workspaceId: row.workspaceId,\n membershipId: row.membershipId,\n summary: row.summary,\n vid: row.vid,\n lastUpdated: row.lastUpdated,\n denormalizedTenantName: row.denormalizedTenantName,\n denormalizedUserName: row.denormalizedUserName,\n denormalizedWorkspaceName: row.denormalizedWorkspaceName,\n }),\n );\n\n return { items, cursor: result.cursor ?? null };\n}\n"],"mappings":"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","names":[]}
|