graphddb 0.5.2 → 0.5.3
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/README.md +8 -0
- package/dist/cdc/index.d.ts +37 -0
- package/dist/cdc/index.js +29 -0
- package/dist/{chunk-W3GEJPPV.js → chunk-CCIVET5K.js} +66 -1024
- package/dist/{chunk-QBXLQNXY.js → chunk-M6URQOAW.js} +4 -1
- package/dist/chunk-MMVHOUM4.js +24 -0
- package/dist/chunk-PDUVTYC5.js +992 -0
- package/dist/{chunk-H5TUW2WR.js → chunk-Y7XV5QL2.js} +3556 -3547
- package/dist/cli.js +917 -19
- package/dist/from-change-DQK2Jm9R.d.ts +327 -0
- package/dist/index-CtDBo8Se.d.ts +690 -0
- package/dist/index.d.ts +7 -1112
- package/dist/index.js +22 -39
- package/dist/linter/index.d.ts +126 -0
- package/dist/linter/index.js +36 -0
- package/dist/{types-m1Ect6hG.d.ts → maintenance-view-adapter-D5t9taTE.d.ts} +234 -182
- package/dist/registry-BD_5Rm5C.d.ts +76 -0
- package/dist/relation-depth-DLkhG0xX.d.ts +36 -0
- package/dist/spec/index.d.ts +4 -0
- package/dist/spec/index.js +54 -0
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +5 -4
- package/docs/doc-sample.md +263 -0
- package/docs/docs-generation.md +183 -0
- package/package.json +46 -3
- package/dist/chunk-MCKGQKYU.js +0 -15
- package/dist/typescript-ZUQEBJRV.js +0 -210764
package/dist/testing/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createCdcEmulator
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-M6URQOAW.js";
|
|
4
4
|
import {
|
|
5
5
|
ClientManager,
|
|
6
6
|
MetadataRegistry,
|
|
7
|
-
TableMapping,
|
|
8
7
|
resolveModelClass
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import
|
|
8
|
+
} from "../chunk-CCIVET5K.js";
|
|
9
|
+
import {
|
|
10
|
+
TableMapping
|
|
11
|
+
} from "../chunk-PDUVTYC5.js";
|
|
11
12
|
|
|
12
13
|
// src/memory/memory-store.ts
|
|
13
14
|
function deepClone(value) {
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# UserPermissions Table Specification
|
|
2
|
+
|
|
3
|
+
> Generated by `graphddb generate docs`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table Overview
|
|
8
|
+
|
|
9
|
+
| Item | Value |
|
|
10
|
+
|------|-------|
|
|
11
|
+
| Table | `UserPermissions` |
|
|
12
|
+
| Description | User / Group / Permission Management |
|
|
13
|
+
| Billing Mode | PAY_PER_REQUEST |
|
|
14
|
+
| Streams | NEW_AND_OLD_IMAGES |
|
|
15
|
+
| TTL | Disabled |
|
|
16
|
+
| PITR | Enabled |
|
|
17
|
+
| Table Class | STANDARD |
|
|
18
|
+
| Encryption | AWS Managed SSE |
|
|
19
|
+
| CloudFormation | `cloudformation.yaml` |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Entity Relationship Diagram
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
graph TD
|
|
27
|
+
User -->|hasMany| Membership
|
|
28
|
+
Membership -->|belongsTo| Group
|
|
29
|
+
User -->|hasMany| Permission
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Physical Key Schema
|
|
35
|
+
|
|
36
|
+
| Model | PK | SK | GSI1 PK | GSI1 SK |
|
|
37
|
+
|------|------|------|------|------|
|
|
38
|
+
| User | `USER#{userId}` | `PROFILE` | `EMAIL#{email}` | `USER#{userId}` |
|
|
39
|
+
| Group | `GROUP#{groupId}` | `PROFILE` | | |
|
|
40
|
+
| Membership | `GROUP#{groupId}` | `USER#{userId}` | `USER#{userId}` | `GROUP#{groupId}` |
|
|
41
|
+
| Permission | `USER#{userId}` | `PERMISSION#{permission}` | | |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Property Matrix
|
|
46
|
+
|
|
47
|
+
| Property | Type | Description | User | Group | Membership | Permission |
|
|
48
|
+
|----------|------|-------------|------|------|------|------|
|
|
49
|
+
| userId | string | User ID | PK | | GSI1 PK | PK |
|
|
50
|
+
| groupId | string | Group ID | | PK | PK | |
|
|
51
|
+
| permission | string | Permission Name | | | | SK |
|
|
52
|
+
| email | string | Login Email | GSI1 PK | | | |
|
|
53
|
+
| name | string | Display Name | ✓ | ✓ | | |
|
|
54
|
+
| role | string | Group Role | | | ✓ | |
|
|
55
|
+
| createdAt | datetime | Created Time | ✓ | ✓ | ✓ | ✓ |
|
|
56
|
+
|
|
57
|
+
Legend: **PK** primary partition key · **SK** primary sort key · **GSI1 PK/SK** GSI1 keys · **✓** normal attribute
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Entity Details
|
|
62
|
+
|
|
63
|
+
### User
|
|
64
|
+
|
|
65
|
+
- **Key**: `PK = USER#{userId}` / `SK = PROFILE`
|
|
66
|
+
- **GSI1**: `PK = EMAIL#{email}` / `SK = USER#{userId}`
|
|
67
|
+
- **Relations**: `groups` → Membership → Group (hasMany), `permissions` → Permission (hasMany)
|
|
68
|
+
|
|
69
|
+
| Field | Type | Description |
|
|
70
|
+
|------|------|------|
|
|
71
|
+
| userId | string | User ID |
|
|
72
|
+
| email | string | Login Email |
|
|
73
|
+
| name | string | Display Name |
|
|
74
|
+
| createdAt | datetime | Created Time |
|
|
75
|
+
|
|
76
|
+
### Group
|
|
77
|
+
|
|
78
|
+
- **Key**: `PK = GROUP#{groupId}` / `SK = PROFILE`
|
|
79
|
+
- **Maintained**: `memberCount` (counter), `groupSnapshots` on User (embedded snapshot)
|
|
80
|
+
|
|
81
|
+
| Field | Type | Description |
|
|
82
|
+
|------|------|------|
|
|
83
|
+
| groupId | string | Group ID |
|
|
84
|
+
| name | string | Display Name |
|
|
85
|
+
| createdAt | datetime | Created Time |
|
|
86
|
+
|
|
87
|
+
### Membership
|
|
88
|
+
|
|
89
|
+
- **Key**: `PK = GROUP#{groupId}` / `SK = USER#{userId}`
|
|
90
|
+
- **GSI1**: `PK = USER#{userId}` / `SK = GROUP#{groupId}`
|
|
91
|
+
|
|
92
|
+
| Field | Type | Description |
|
|
93
|
+
|------|------|------|
|
|
94
|
+
| groupId | string | Group ID |
|
|
95
|
+
| userId | string | User ID |
|
|
96
|
+
| role | string | Group Role |
|
|
97
|
+
| createdAt | datetime | Created Time |
|
|
98
|
+
|
|
99
|
+
### Permission
|
|
100
|
+
|
|
101
|
+
- **Key**: `PK = USER#{userId}` / `SK = PERMISSION#{permission}`
|
|
102
|
+
|
|
103
|
+
| Field | Type | Description |
|
|
104
|
+
|------|------|------|
|
|
105
|
+
| userId | string | User ID |
|
|
106
|
+
| permission | string | Permission Name |
|
|
107
|
+
| createdAt | datetime | Created Time |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Access Patterns
|
|
112
|
+
|
|
113
|
+
Each query resolves to a physical operation, an index (PK or GSI), and a projection.
|
|
114
|
+
The matrix summarizes; the contracts below give the input/output and execution for each.
|
|
115
|
+
|
|
116
|
+
| Query | Index | Relation | BatchGet | Cursor |
|
|
117
|
+
|------|------|------|------|------|
|
|
118
|
+
| `User.query(userId)` | PK | | | |
|
|
119
|
+
| `User.queryByEmail(email)` | GSI1 | | | |
|
|
120
|
+
| `User.groups(userId)` | PK | ✓ | ✓ | ✓ |
|
|
121
|
+
| `Group.members(groupId)` | PK | ✓ | ✓ | ✓ |
|
|
122
|
+
| `User.permissions(userId)` | PK | ✓ | | ✓ |
|
|
123
|
+
|
|
124
|
+
### `User.query(userId)`
|
|
125
|
+
|
|
126
|
+
Returns a single user by primary key.
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
Input: { userId: string }
|
|
130
|
+
Output: User
|
|
131
|
+
Resolve: PK = USER#{userId} → Query → Projection(name, email)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```mermaid
|
|
135
|
+
flowchart LR
|
|
136
|
+
In["userId"] --> Key["PK = USER#{userId}"] --> Q["Query"] --> Out["User"]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `User.queryByEmail(email)`
|
|
140
|
+
|
|
141
|
+
Returns a single user by email (unique GSI).
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
Input: { email: string }
|
|
145
|
+
Output: User
|
|
146
|
+
Resolve: GSI1 PK = EMAIL#{email} → Query → Projection(userId, name)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```mermaid
|
|
150
|
+
flowchart LR
|
|
151
|
+
In["email"] --> Key["GSI1 PK = EMAIL#{email}"] --> Q["Query"] --> Out["User"]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `User.groups(userId)`
|
|
155
|
+
|
|
156
|
+
Returns the groups a user belongs to (paged).
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
Input: { userId: string, limit?: number, cursor?: string }
|
|
160
|
+
Output: Page<Group>
|
|
161
|
+
Resolve: Query(User) → Query(Membership by PK) → BatchGet(Group)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```mermaid
|
|
165
|
+
flowchart LR
|
|
166
|
+
User -- "PK" --> Membership -- "BatchGet" --> Group
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `Group.members(groupId)`
|
|
170
|
+
|
|
171
|
+
Returns the members of a group (paged).
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
Input: { groupId: string, limit?: number, cursor?: string }
|
|
175
|
+
Output: Page<User>
|
|
176
|
+
Resolve: Query(Group) → Query(Membership by PK) → BatchGet(User)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
```mermaid
|
|
180
|
+
flowchart LR
|
|
181
|
+
Group -- "PK" --> Membership -- "BatchGet" --> User
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Mutation Contracts
|
|
187
|
+
|
|
188
|
+
### `User.update()`
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
Input: { userId: string, name?: string, email?: string }
|
|
192
|
+
Output: User
|
|
193
|
+
Resolve: TransactWrite → User item
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `Membership.create()`
|
|
197
|
+
|
|
198
|
+
Creating a membership also maintains `Group.memberCount` in the same transaction.
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
Input: { groupId: string, userId: string, role: string }
|
|
202
|
+
Output: Membership
|
|
203
|
+
Resolve: TransactWrite → Membership item + Group.memberCount (ADD +1)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
```mermaid
|
|
207
|
+
flowchart LR
|
|
208
|
+
Create["Membership.create"] --> TW["TransactWrite"]
|
|
209
|
+
TW --> M["Membership"]
|
|
210
|
+
TW --> C["Group.memberCount (+1)"]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Maintained Access Paths
|
|
216
|
+
|
|
217
|
+
Write-side projections kept in sync automatically, within the source write's transaction
|
|
218
|
+
(or via the CDC stream for `updateMode: 'stream'`).
|
|
219
|
+
|
|
220
|
+
| Source | Target | Pattern | Update |
|
|
221
|
+
|---------|--------|--------|--------|
|
|
222
|
+
| Membership | Group.memberCount | counter | ADD +1 / −1 on create / remove |
|
|
223
|
+
| Group | User.groupSnapshots | embeddedSnapshot | project Group fields into User |
|
|
224
|
+
|
|
225
|
+
```mermaid
|
|
226
|
+
flowchart LR
|
|
227
|
+
Membership -- "create / remove" --> Counter["ADD ±1"] --> MC["Group.memberCount"]
|
|
228
|
+
Group -- "projection" --> Snap["Embedded Snapshot"] --> GS["User.groupSnapshots"]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## CDC
|
|
234
|
+
|
|
235
|
+
`@cdcProjected` models expose `fromChange` / `subscribe` to parse the change stream into
|
|
236
|
+
typed records. Delivery and idempotency are the consumer's responsibility.
|
|
237
|
+
|
|
238
|
+
```yaml
|
|
239
|
+
Contract: User.subscribe
|
|
240
|
+
Input: ChangeEvent<User>
|
|
241
|
+
Output: [User | null, User | null] # [oldRecord, newRecord]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
```mermaid
|
|
245
|
+
flowchart LR
|
|
246
|
+
Mutate --> Stream["DynamoDB Stream"] --> CE["ChangeEvent"]
|
|
247
|
+
CE --> FC["User.fromChange()"] --> Sub["subscribe()"] --> Consumer
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## CloudFormation
|
|
253
|
+
|
|
254
|
+
Generated by `graphddb generate cloudformation` (see `cloudformation.yaml`).
|
|
255
|
+
|
|
256
|
+
| Resource | Description |
|
|
257
|
+
|------|------|
|
|
258
|
+
| `AWS::DynamoDB::Table` | Physical table |
|
|
259
|
+
| GlobalSecondaryIndexes | GSI definitions (GSI1 …) |
|
|
260
|
+
| StreamSpecification | NEW_AND_OLD_IMAGES |
|
|
261
|
+
| TimeToLiveSpecification | TTL (when a TTL attribute is declared) |
|
|
262
|
+
| PointInTimeRecovery | PITR |
|
|
263
|
+
| Auto Scaling | Optional (PROVISIONED mode) |
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# GraphDDB — Docs generation
|
|
2
|
+
|
|
3
|
+
`graphddb generate docs` renders a **human-facing model specification** —
|
|
4
|
+
Markdown with embedded Mermaid diagrams — directly from your TypeScript models.
|
|
5
|
+
It reads the same serializable manifest / operations the Python bridge and the
|
|
6
|
+
CloudFormation generator use (it loads your entry model, builds the manifest and
|
|
7
|
+
operation specs from the shared metadata registry, and renders the document), so
|
|
8
|
+
the spec never drifts from the code: your models are the single source of truth.
|
|
9
|
+
|
|
10
|
+
Output is **deterministic** — the same model set always produces the same
|
|
11
|
+
document — and the layout is defined by **Handlebars** templates you can override
|
|
12
|
+
per-section and extend with your own helpers.
|
|
13
|
+
|
|
14
|
+
> This document is the reference for the shipped `generate docs` command: its
|
|
15
|
+
> options, the sections it produces, and how to customize the templates.
|
|
16
|
+
|
|
17
|
+
### Related specifications
|
|
18
|
+
|
|
19
|
+
- [`spec.md`](./spec.md) — the core API: entities, structured keys / GSIs,
|
|
20
|
+
relations, queries.
|
|
21
|
+
- [`cloudformation.md`](./cloudformation.md) — the sibling generator; the
|
|
22
|
+
`--billing-mode` / `--stream` flags are shared with it.
|
|
23
|
+
- [`design-patterns.md`](./design-patterns.md) — maintained access paths and the
|
|
24
|
+
`updateMode: 'stream'` signal that drives `--stream auto`.
|
|
25
|
+
|
|
26
|
+
## Overview
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
graphddb generate docs --entry models.ts --out doc.md
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- **`--entry`** loads the TypeScript (or pre-compiled `.js`/`.mjs`) module that
|
|
33
|
+
registers your entity models as a side effect of import. TypeScript modules are
|
|
34
|
+
transpiled on demand via `tsx` (an optional peer dependency — install it with
|
|
35
|
+
`npm i -D tsx`).
|
|
36
|
+
- **`--out`** accepts either a **file** or a **directory**. A path ending in
|
|
37
|
+
`.md` (e.g. `--out doc.md`) writes the single Markdown file at exactly that
|
|
38
|
+
path, creating parent directories as needed — this is the preferred usage.
|
|
39
|
+
Any other value is treated as a **directory** and the document is written as
|
|
40
|
+
`<dir>/index.md` (backward compatible). Either way the command prints a JSON
|
|
41
|
+
result (`{"status":"ok","outDir":…,"files":[…]}`) to stdout, where `files`
|
|
42
|
+
reports the written path(s).
|
|
43
|
+
- **`--queries`** (optional) points at the module exporting your `queries` /
|
|
44
|
+
`commands` (the `defineQueries` / `defineCommands` maps). It powers the Access
|
|
45
|
+
Patterns and Mutation Contracts sections; omit it and those sections are empty.
|
|
46
|
+
Defaults to the entry module.
|
|
47
|
+
|
|
48
|
+
To also document your access patterns and mutations:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
graphddb generate docs --entry models.ts --queries definitions.ts --out docs/
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Output sections
|
|
55
|
+
|
|
56
|
+
The generated `index.md` is composed, in this fixed order, from:
|
|
57
|
+
|
|
58
|
+
| Section | Source | Contents |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| **Table Overview** | manifest + flags | Table name, billing mode, streams, TTL, and the deploy-time settings. |
|
|
61
|
+
| **Entity Relationship Diagram** | manifest relations | A Mermaid `graph TD` of the `hasMany` / `hasOne` / `belongsTo` edges. |
|
|
62
|
+
| **Physical Key Schema** | manifest keys / GSIs | A table of each model's `PK` / `SK` and per-GSI key templates. |
|
|
63
|
+
| **Property Matrix** | manifest fields | Each property's role (PK / SK / GSI key / plain attribute) across entities. |
|
|
64
|
+
| **Entity Details** | manifest | Per-entity key, GSIs, relations, maintained fields, and field table. |
|
|
65
|
+
| **Access Patterns** | operations | A summary matrix plus, per query, the input/output contract, a `Resolve:` line, and a Mermaid execution flowchart. |
|
|
66
|
+
| **Mutation Contracts** | operations | Per command, the input/output and resolution. |
|
|
67
|
+
| **Maintained Access Paths** | metadata registry | Write-side projections kept in sync (counter / embedded snapshot), with a Mermaid diagram. |
|
|
68
|
+
| **CDC** | metadata registry | For each `@cdcProjected()` model, the `subscribe` / `fromChange` contract and a stream diagram. |
|
|
69
|
+
| **CloudFormation** | manifest | A summary of the resources `generate cloudformation` emits. |
|
|
70
|
+
|
|
71
|
+
The Table Overview's **billing** and **streams** are resolved from the CLI flags
|
|
72
|
+
(shared with `generate cloudformation`); deploy-time-only settings that have no
|
|
73
|
+
flag (PITR, table class, encryption) render as `as configured at deployment`.
|
|
74
|
+
|
|
75
|
+
## Options
|
|
76
|
+
|
|
77
|
+
| Option | Default | Description |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `--entry <file>` | (required) | Entry module registering the entity models. |
|
|
80
|
+
| `--out <path>` | (required) | Output path. A `*.md` file is written verbatim at that path; any other value is a directory and `index.md` is written inside it. |
|
|
81
|
+
| `--queries <file>` | entry module | Module exporting `queries` / `commands` for Access Patterns / Mutation Contracts. |
|
|
82
|
+
| `--format <format>` | `markdown` | Output format (only `markdown` today). |
|
|
83
|
+
| `--split <mode>` | `none` | `none` emits a single `index.md`. `entity` is reserved for a future per-entity split. |
|
|
84
|
+
| `--template-dir <dir>` | — | Directory of override `<partial>.hbs` templates. |
|
|
85
|
+
| `--helpers <file>` | — | JS module exporting extra Handlebars helpers. |
|
|
86
|
+
| `--billing-mode <mode>` | `PAY_PER_REQUEST` | Billing mode shown in the Table Overview (shared with `generate cloudformation`). |
|
|
87
|
+
| `--stream <mode>` | `auto` | Streams state in the Table Overview: `auto` detects stream-based maintenance (`updateMode: 'stream'`); `on` / `off` force it. |
|
|
88
|
+
|
|
89
|
+
## Customizing the templates
|
|
90
|
+
|
|
91
|
+
The document is rendered from a set of bundled **Handlebars partials**, one per
|
|
92
|
+
section:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
index · table-overview · er-diagram · key-schema · property-matrix
|
|
96
|
+
· entity · access-pattern · maintained · cdc · cloudformation
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`index` is the document skeleton; it renders each section partial in order. All
|
|
100
|
+
partials reference only a normalized **view model** (the section headings, table
|
|
101
|
+
rows, diagram nodes are precomputed), so a custom template is just a loop over
|
|
102
|
+
ready-to-print data — you never have to reach into the raw manifest.
|
|
103
|
+
|
|
104
|
+
### `--template-dir` (per-section override)
|
|
105
|
+
|
|
106
|
+
Point `--template-dir` at a directory containing any `<partial>.hbs` files. Each
|
|
107
|
+
file whose name matches a bundled partial **replaces** it; every partial you do
|
|
108
|
+
**not** provide falls back to the bundled default. You only write the sections
|
|
109
|
+
you want to change — there is no need to copy the whole set.
|
|
110
|
+
|
|
111
|
+
For example, to replace just the CloudFormation section:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
doc-templates/
|
|
115
|
+
cloudformation.hbs
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```handlebars
|
|
119
|
+
{{! doc-templates/cloudformation.hbs }}
|
|
120
|
+
## Infrastructure
|
|
121
|
+
|
|
122
|
+
The table `{{table}}` is provisioned by our platform team — see the internal
|
|
123
|
+
runbook. Generated CloudFormation lives in `{{cfnFile}}`.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
graphddb generate docs --entry models.ts --out docs/ --template-dir doc-templates/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Every other section still renders from the bundled partials.
|
|
131
|
+
|
|
132
|
+
### `--helpers` (extra Handlebars helpers)
|
|
133
|
+
|
|
134
|
+
The generator registers a small built-in helper set — `eq`, `join`, `pascal`,
|
|
135
|
+
`mermaidId`, and `codeOrEmpty`. Pass `--helpers` a JS module to register more (a
|
|
136
|
+
custom helper of the same name overrides a built-in). The module exports its
|
|
137
|
+
helpers as a `helpers` named export (or the default export):
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
// doc-helpers.mjs
|
|
141
|
+
export const helpers = {
|
|
142
|
+
shout: (value) => String(value).toUpperCase(),
|
|
143
|
+
badge: (text) => ``,
|
|
144
|
+
};
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
graphddb generate docs --entry models.ts --out docs/ \
|
|
149
|
+
--template-dir doc-templates/ --helpers doc-helpers.mjs
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Your helpers are then callable from any partial (bundled or overridden):
|
|
153
|
+
|
|
154
|
+
```handlebars
|
|
155
|
+
{{shout table}}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## The view model
|
|
159
|
+
|
|
160
|
+
Templates receive a single normalized view model with these top-level fields —
|
|
161
|
+
the vocabulary a custom template can rely on:
|
|
162
|
+
|
|
163
|
+
| Field | Shape | Used by |
|
|
164
|
+
| --- | --- | --- |
|
|
165
|
+
| `title` / `table` | strings | headings, Table Overview |
|
|
166
|
+
| `overview` | `{ item, value }[]` | Table Overview |
|
|
167
|
+
| `entityNames` | `string[]` | Property Matrix columns |
|
|
168
|
+
| `relationEdges` | `{ source, target, label }[]` | ER diagram |
|
|
169
|
+
| `gsiColumns` / `keySchema` | GSI names / `{ model, pk, sk, gsis }[]` | Key Schema |
|
|
170
|
+
| `propertyMatrix` | `{ property, type, description, cells }[]` | Property Matrix |
|
|
171
|
+
| `entities` | per-entity `{ name, pk, sk, gsis, relations, maintained, fields }` | Entity Details |
|
|
172
|
+
| `accessMatrix` / `accessPatterns` | matrix rows / `{ signature, input, output, resolve, diagram, … }` | Access Patterns |
|
|
173
|
+
| `mutationContracts` | `{ signature, input, output, resolve }[]` | Mutation Contracts |
|
|
174
|
+
| `maintainedPaths` | `{ source, target, pattern, update }[]` | Maintained Access Paths |
|
|
175
|
+
| `cdcEntries` | `{ model }[]` | CDC |
|
|
176
|
+
| `cfnResources` / `cfnFile` | `{ resource, description }[]` / string | CloudFormation |
|
|
177
|
+
|
|
178
|
+
## Scope
|
|
179
|
+
|
|
180
|
+
The Access Patterns are described to the extent resolvable at generation time —
|
|
181
|
+
the operation type, the index, the key template, the projection, and the
|
|
182
|
+
cardinality (single vs. paged). Actual read-capacity cost and row counts require
|
|
183
|
+
runtime information and are out of scope.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphddb",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Graph data modeling on DynamoDB with adjacency list pattern",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
"./testing": {
|
|
18
18
|
"types": "./dist/testing/index.d.ts",
|
|
19
19
|
"import": "./dist/testing/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./spec": {
|
|
22
|
+
"types": "./dist/spec/index.d.ts",
|
|
23
|
+
"import": "./dist/spec/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./linter": {
|
|
26
|
+
"types": "./dist/linter/index.d.ts",
|
|
27
|
+
"import": "./dist/linter/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./cdc": {
|
|
30
|
+
"types": "./dist/cdc/index.d.ts",
|
|
31
|
+
"import": "./dist/cdc/index.js"
|
|
20
32
|
}
|
|
21
33
|
},
|
|
22
34
|
"bin": {
|
|
@@ -41,9 +53,36 @@
|
|
|
41
53
|
"gen:cli": "cli-contracts generate",
|
|
42
54
|
"gen:cli:check": "cli-contracts generate --dry-run",
|
|
43
55
|
"clean": "rm -rf dist",
|
|
56
|
+
"size": "size-limit",
|
|
57
|
+
"size:why": "size-limit --why",
|
|
44
58
|
"docker:up": "docker compose -f docker-compose.test.yml up -d",
|
|
45
59
|
"docker:down": "docker compose -f docker-compose.test.yml down"
|
|
46
60
|
},
|
|
61
|
+
"size-limit": [
|
|
62
|
+
{
|
|
63
|
+
"name": "runtime core (DDBModel + authoring)",
|
|
64
|
+
"path": "dist/index.js",
|
|
65
|
+
"import": "{ DDBModel, model, string, number, key, k, executeQuery, executeList, executeExplain }",
|
|
66
|
+
"limit": "42 KB"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "runtime core (import *)",
|
|
70
|
+
"path": "dist/index.js",
|
|
71
|
+
"limit": "80 KB"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "graphddb/testing",
|
|
75
|
+
"path": "dist/testing/index.js",
|
|
76
|
+
"import": "{ createTestDB }",
|
|
77
|
+
"limit": "12 KB"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "graphddb/spec (build-time)",
|
|
81
|
+
"path": "dist/spec/index.js",
|
|
82
|
+
"import": "{ buildBridgeBundle }",
|
|
83
|
+
"limit": "20 KB"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
47
86
|
"peerDependencies": {
|
|
48
87
|
"@aws-sdk/client-dynamodb": "^3.0.0",
|
|
49
88
|
"@aws-sdk/lib-dynamodb": "^3.0.0",
|
|
@@ -63,11 +102,13 @@
|
|
|
63
102
|
"devDependencies": {
|
|
64
103
|
"@aws-sdk/client-dynamodb": "^3.700.0",
|
|
65
104
|
"@aws-sdk/lib-dynamodb": "^3.700.0",
|
|
105
|
+
"@size-limit/preset-small-lib": "^11.0.0",
|
|
66
106
|
"@types/node": "^22.20.0",
|
|
67
107
|
"cli-contracts": "^0.33.14",
|
|
68
108
|
"dynamodb-onetable": "^2.7.7",
|
|
69
109
|
"dynamodb-toolbox": "^2.9.0",
|
|
70
110
|
"electrodb": "^3.9.1",
|
|
111
|
+
"size-limit": "^11.0.0",
|
|
71
112
|
"tsup": "^8.0.0",
|
|
72
113
|
"tsx": "^4.22.4",
|
|
73
114
|
"typescript": "^5.5.0",
|
|
@@ -79,9 +120,11 @@
|
|
|
79
120
|
},
|
|
80
121
|
"license": "MIT",
|
|
81
122
|
"dependencies": {
|
|
82
|
-
"commander": "^15.0.0"
|
|
123
|
+
"commander": "^15.0.0",
|
|
124
|
+
"handlebars": "^4.7.9"
|
|
83
125
|
},
|
|
84
126
|
"optionalDependencies": {
|
|
85
127
|
"typescript": "^5.5.0"
|
|
86
|
-
}
|
|
128
|
+
},
|
|
129
|
+
"sideEffects": false
|
|
87
130
|
}
|
package/dist/chunk-MCKGQKYU.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
-
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
8
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
9
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
__require,
|
|
14
|
-
__commonJS
|
|
15
|
-
};
|