@aotter/mantle 0.1.0-alpha.13 → 0.1.0-alpha.15
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/docs/adapter-guide.md +9 -0
- package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +24 -6
- package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +178 -0
- package/docs/adr/README.md +1 -0
- package/docs/design-atoms.md +11 -8
- package/docs/release-process.md +11 -9
- package/package.json +17 -17
package/docs/adapter-guide.md
CHANGED
|
@@ -106,6 +106,15 @@ optional `/libsql` subpath adapts a caller-owned remote Turso/libSQL client to
|
|
|
106
106
|
the canonical SQLite chain; the default entry has no database-vendor policy.
|
|
107
107
|
Vercel's read-only filesystem and writable `/tmp` are never durable state.
|
|
108
108
|
|
|
109
|
+
### Browser IndexedDB embedding
|
|
110
|
+
|
|
111
|
+
`@aotter/mantle-indexeddb` implements the same required semantic storage ports
|
|
112
|
+
over one application-owned IndexedDB database. It keeps browser globals out of
|
|
113
|
+
Runtime Core, supports declarative Views with a documented O(n) collection
|
|
114
|
+
scan, and exposes `deleteDatabase()` only on the concrete adapter. The host owns
|
|
115
|
+
database naming, `navigator.storage` persistence requests, active-runtime
|
|
116
|
+
selection, UI invalidation, and any remote synchronization.
|
|
117
|
+
|
|
109
118
|
## HTTP and MCP surfaces
|
|
110
119
|
|
|
111
120
|
The runtime is a library, not an HTTP server. A new adapter must mount equivalent framework routes:
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
**Status:** Accepted
|
|
4
4
|
|
|
5
|
-
**Date:** 2026-08-16; last amended 2026-
|
|
5
|
+
**Date:** 2026-08-16; last amended 2026-09-01
|
|
6
6
|
|
|
7
7
|
**Related:** [#656](https://github.com/aotter/mantle/issues/656),
|
|
8
8
|
[#662](https://github.com/aotter/mantle/issues/662),
|
|
9
|
+
[#759](https://github.com/aotter/mantle/issues/759),
|
|
10
|
+
[#760](https://github.com/aotter/mantle/issues/760),
|
|
9
11
|
[#546](https://github.com/aotter/mantle/issues/546), ADR-0008, ADR-0009,
|
|
10
12
|
ADR-0011, ADR-0018
|
|
11
13
|
|
|
@@ -106,6 +108,15 @@ Concrete D1/SQLite drivers and SQL repositories remain implementation details.
|
|
|
106
108
|
An existing application may either pass its already-owned database/client to
|
|
107
109
|
an official adapter or implement the semantic ports over its own tables.
|
|
108
110
|
|
|
111
|
+
`@aotter/mantle-indexeddb` is the optional browser storage implementation of
|
|
112
|
+
the same semantic ports. One adapter exclusively owns one application-selected
|
|
113
|
+
database name, uses structured-clone persistence and IndexedDB transaction
|
|
114
|
+
completion as its write boundary, and exposes database deletion only on the
|
|
115
|
+
concrete adapter. Runtime Core gains no browser global, browser facade,
|
|
116
|
+
namespace, persistence request, reactive binding, or synchronization port.
|
|
117
|
+
Declarative browser Views use a documented O(n) scan until measured use proves
|
|
118
|
+
an IndexedDB query planner necessary.
|
|
119
|
+
|
|
109
120
|
Declarative Views compile to logical plans once. Storage preparation lowers
|
|
110
121
|
those plans to native queries. The v0.1 `View.spec.sql` form remains explicitly
|
|
111
122
|
SQLite-only and is rejected by unsupported storage during preparation; Mantle
|
|
@@ -123,11 +134,18 @@ select a surface and bind transport or browser lifecycle, but do not rescan raw
|
|
|
123
134
|
manifests or maintain a second registry.
|
|
124
135
|
|
|
125
136
|
`@aotter/mantle-web/webmcp` is an opt-in host binding over that projection. It
|
|
126
|
-
feature-detects `document.modelContext`,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
feature-detects `document.modelContext`, adds public capabilities without
|
|
138
|
+
replacing existing host tools, and uses the registration `AbortSignal` only for
|
|
139
|
+
teardown. A browser-local host supplies the projected capabilities and a
|
|
140
|
+
late-bound invoker; Procedure calls retain their explicit MCP Trigger identity.
|
|
141
|
+
For a server-backed host, the Cloudflare adapter publishes a minimal public View
|
|
142
|
+
catalog at `GET /api/views`; the binding validates that wire catalog and invokes
|
|
143
|
+
the existing same-origin `GET /api/views/<name>` route. The catalog contains no
|
|
144
|
+
raw manifest or staff capability.
|
|
145
|
+
Invocation hooks may drive host UI effects but cannot replace Runtime
|
|
146
|
+
validation, authorization, dispatch, or domain results. The binding does not
|
|
147
|
+
add browser globals to Runtime Core, expose staff capabilities, or introduce a
|
|
148
|
+
second manifest/runtime path.
|
|
131
149
|
|
|
132
150
|
### Naming and code generation
|
|
133
151
|
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# ADR-0020: Builtin Handler Contracts and Matched Upsert
|
|
2
|
+
|
|
3
|
+
**Status:** Accepted
|
|
4
|
+
|
|
5
|
+
**Date:** 2026-09-01
|
|
6
|
+
|
|
7
|
+
**Related:** [#765](https://github.com/aotter/mantle/issues/765),
|
|
8
|
+
[#766](https://github.com/aotter/mantle/issues/766),
|
|
9
|
+
ADR-0008, ADR-0010, ADR-0014, ADR-0019
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
Mantle Procedures can bind to standard entry-mutation operations using `handler.kind: builtin` (e.g. `create`, `update`, `delete`, `archive`, `upsert`).
|
|
14
|
+
|
|
15
|
+
Before this ADR:
|
|
16
|
+
1. **No static contract validation**: Procedure input JSON Schema contracts were not statically verified against the requirements of their builtin operations during manifest linking (`ValidateManifestsUseCase`). Invalid contracts (e.g. `update` missing `id` or `expectedVersion`, nullable union types like `type: ["string", "null"]`, or `archive` on operational Schemas) were only caught at runtime via `requireField` or runtime assertions, causing valid-looking manifests to fail during invocation.
|
|
17
|
+
2. **Missing natural key upsert (`handler.match`)**: Built-in `upsert` only supported legacy ID-based lookup (`id` + `expectedVersion`), requiring client knowledge of internal system IDs. Real-world domains require idempotent upserts matching natural keys (such as `slug`, `siteKey`, or composite unique keys like `[slug, locale]`).
|
|
18
|
+
3. **Concurrency and race conditions**: Matched upsert must handle concurrent writers safely. When two concurrent writers miss preflight lookup, storage-level unique constraints must catch the conflict and surface structured `CONFLICT` diagnostics without retrying or corrupting entries.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
### 1. Static Contract Validation for Builtin Handlers
|
|
23
|
+
|
|
24
|
+
Manifest linking (`ManifestGraphValidator.ts`) now validates Procedure `input` schemas against the requirements of their builtin `op`:
|
|
25
|
+
|
|
26
|
+
- **Diagnostic Code**: `BUILTIN_HANDLER_CONTRACT_INVALID` (phase: `validate`).
|
|
27
|
+
- **Common rule**: `input` must be an `object` schema (`type: "object"`).
|
|
28
|
+
- **`update`**:
|
|
29
|
+
- `properties.id` must be strict, non-nullable `string` (`type: "string"`, not union array, not `nullable: true`).
|
|
30
|
+
- `properties.expectedVersion` must be strict, non-nullable `number` (`type: "number"`, not union array, not `nullable: true`).
|
|
31
|
+
- `required` must include both `"id"` and `"expectedVersion"`.
|
|
32
|
+
- **`delete`**:
|
|
33
|
+
- `properties.id` must be strict, non-nullable `string`.
|
|
34
|
+
- `required` must include `"id"`.
|
|
35
|
+
- **`archive`**:
|
|
36
|
+
- Target Schema must have `lifecycle: "publishing"` (operational Schemas have no lifecycle transitions and cannot be archived).
|
|
37
|
+
- `properties.id` must be strict, non-nullable `string`.
|
|
38
|
+
- `required` must include `"id"`.
|
|
39
|
+
- **`upsert` (legacy mode without `match`)**:
|
|
40
|
+
- If either `id` or `expectedVersion` is declared, both must be declared with strict string and number types respectively. Neither is in `required` because the create branch accepts new entries without IDs.
|
|
41
|
+
|
|
42
|
+
### 2. Matched Upsert Grammar and Static Contract (`handler.match`)
|
|
43
|
+
|
|
44
|
+
Procedures with `op: "upsert"` may declare `match`:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
48
|
+
kind: Procedure
|
|
49
|
+
metadata:
|
|
50
|
+
name: upsertArticleBySlug
|
|
51
|
+
spec:
|
|
52
|
+
input:
|
|
53
|
+
type: object
|
|
54
|
+
properties:
|
|
55
|
+
slug:
|
|
56
|
+
type: string
|
|
57
|
+
title:
|
|
58
|
+
type: string
|
|
59
|
+
body:
|
|
60
|
+
type: string
|
|
61
|
+
required:
|
|
62
|
+
- slug
|
|
63
|
+
- title
|
|
64
|
+
output:
|
|
65
|
+
type: object
|
|
66
|
+
handler:
|
|
67
|
+
kind: builtin
|
|
68
|
+
op: upsert
|
|
69
|
+
schema: articles
|
|
70
|
+
match:
|
|
71
|
+
- slug
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Grammar and parser validation rules (`ManifestParser.ts`)**:
|
|
75
|
+
- `match` is allowed in `spec.handler` only when `handler.kind === "builtin"` and `op === "upsert"`.
|
|
76
|
+
- `match` must be a non-empty array of unique, non-empty field names.
|
|
77
|
+
|
|
78
|
+
**Static manifest validation rules (`ManifestGraphValidator.ts`)**:
|
|
79
|
+
- `handler.match` must exactly match one declared unique index in the target Schema's `spec.uniqueIndexes` (matching length, field names, and order).
|
|
80
|
+
- Every field in `handler.match` must be declared in the target Schema's `spec.schema.properties`.
|
|
81
|
+
- Every field in `handler.match` must be declared in Procedure `input.properties` and listed in `input.required`.
|
|
82
|
+
- Procedure `input` must NOT declare `id` or `expectedVersion` when using `match`.
|
|
83
|
+
|
|
84
|
+
### 3. Runtime Semantics and Atomic Conflict Handling (`InvokeBuiltinUseCase.ts`)
|
|
85
|
+
|
|
86
|
+
When executing matched upsert:
|
|
87
|
+
1. Extract matching field values from `input`.
|
|
88
|
+
2. Query existing entry using `entries.findByDataFields({ collection, fields })`.
|
|
89
|
+
3. **If found**: Execute update path (`opUpdate`):
|
|
90
|
+
- Merge input into existing data using `projectUpdateAndStamp`, preserving omitted fields and system bindings.
|
|
91
|
+
- Use `existing.id` and `existing.version` for optimistic concurrency control (OCC).
|
|
92
|
+
- Pass caller's original input to lifecycle hooks (`before_update` / `after_update`).
|
|
93
|
+
4. **If not found**: Execute create path (`opCreate`):
|
|
94
|
+
- Project and stamp data using `projectAndStamp`.
|
|
95
|
+
- Set status to `"published"` (if `lifecycle: "operational"`) or `"draft"` (if `lifecycle: "publishing"`).
|
|
96
|
+
- Pass caller's original input to lifecycle hooks (`before_create` / `after_create`).
|
|
97
|
+
5. **Concurrency & Race Conditions**:
|
|
98
|
+
- Both update and create operations are wrapped in `withConflictDiagnostic`.
|
|
99
|
+
- Storage-level unique constraint violations (e.g. SQLite `SQLITE_CONSTRAINT_UNIQUE`, Postgres `23505`) and version/status mismatches are converted into structured `CONFLICT` diagnostics (HTTP 409).
|
|
100
|
+
- The runtime does not automatically retry matched upsert on conflict, providing deterministic failure semantics under race conditions.
|
|
101
|
+
|
|
102
|
+
## Consequences
|
|
103
|
+
|
|
104
|
+
- **Fail-fast authoring**: Schema and Procedure mismatches are detected during `mantle validate` or test time rather than failing unpredictably at runtime.
|
|
105
|
+
- **Strict type safety**: Nullable union types cannot bypass static contract validation.
|
|
106
|
+
- **Natural key idempotency**: Clients can author natural-key upsert procedures for ingestion and sync pipelines without managing internal mantle IDs.
|
|
107
|
+
- **Safe concurrency across all adapters**: Concurrent writes are guarded by storage-level unique constraints (SQLite/D1 unique indexes, IndexedDB readwrite transaction assertions) and translated to standard `CONFLICT` diagnostics via typed `EntryUniqueConflict`.
|
|
108
|
+
|
|
109
|
+
## Alternatives considered
|
|
110
|
+
|
|
111
|
+
1. **Automatic retry loops on conflict**: Considered having `InvokeBuiltinUseCase` automatically re-query and retry upon catching unique collisions. Rejected because repeated attempts could fire lifecycle hooks (`before_create` / `before_update`) multiple times with unintended side effects (e.g. duplicate webhook notifications or rate limits) and mask true contention. Failing fast with a structured `CONFLICT` diagnostic gives caller control.
|
|
112
|
+
2. **Arbitrary field matching without Schema unique indexes**: Considered allowing `handler.match` on arbitrary Schema properties. Rejected because storage engines cannot enforce uniqueness without dedicated unique constraints/indexes, which would result in race conditions and duplicate entries under concurrent traffic.
|
|
113
|
+
3. **Permissive nullable unions**: Considered allowing `type: ["string", "null"]` in Procedure input schemas for `id`. Rejected because runtime entry mutations strictly require non-null scalar identifiers; allowing nullable schemas would let schema-valid requests crash inside builtin handlers.
|
|
114
|
+
|
|
115
|
+
## How to apply
|
|
116
|
+
|
|
117
|
+
1. **Declare Schema Unique Indexes**:
|
|
118
|
+
```yaml
|
|
119
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
120
|
+
kind: Schema
|
|
121
|
+
metadata:
|
|
122
|
+
name: site-settings
|
|
123
|
+
spec:
|
|
124
|
+
title: Site Settings
|
|
125
|
+
lifecycle: publishing
|
|
126
|
+
schema:
|
|
127
|
+
type: object
|
|
128
|
+
required: [siteKey, theme]
|
|
129
|
+
properties:
|
|
130
|
+
siteKey: { type: string }
|
|
131
|
+
theme: { type: string }
|
|
132
|
+
uniqueIndexes:
|
|
133
|
+
- [siteKey]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
2. **Author a Matched Upsert Procedure**:
|
|
137
|
+
```yaml
|
|
138
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
139
|
+
kind: Procedure
|
|
140
|
+
metadata:
|
|
141
|
+
name: setSiteSetting
|
|
142
|
+
spec:
|
|
143
|
+
input:
|
|
144
|
+
type: object
|
|
145
|
+
required: [siteKey, theme]
|
|
146
|
+
properties:
|
|
147
|
+
siteKey: { type: string }
|
|
148
|
+
theme: { type: string }
|
|
149
|
+
output:
|
|
150
|
+
type: object
|
|
151
|
+
handler:
|
|
152
|
+
kind: builtin
|
|
153
|
+
op: upsert
|
|
154
|
+
schema: site-settings
|
|
155
|
+
match: [siteKey]
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
3. **Validate**:
|
|
159
|
+
Run `mantle validate` to verify input contracts against the declared unique indexes and schema properties.
|
|
160
|
+
|
|
161
|
+
## Implementation status
|
|
162
|
+
|
|
163
|
+
- **`@aotter/mantle-spec`**:
|
|
164
|
+
- `ManifestGrammar.ts`: Added `match?: readonly string[]` to `HandlerBuiltinBinding`.
|
|
165
|
+
- `diagnostic.ts`: Added `BUILTIN_HANDLER_CONTRACT_INVALID` to `DIAGNOSTIC_CODES`.
|
|
166
|
+
- `ManifestParser.ts`: Parser-level validation for `handler.match`.
|
|
167
|
+
- `ManifestGraphValidator.ts`: Static input contract validation in `checkBuiltinHandler`.
|
|
168
|
+
- **`@aotter/mantle-runtime`**:
|
|
169
|
+
- `EntryRow.ts`: Added `EntryUniqueConflict` domain error.
|
|
170
|
+
- `EntryMutationDiagnostics.ts`: `withConflictDiagnostic` converts `EntryUniqueConflict` to `CONFLICT` diagnostic (HTTP 409).
|
|
171
|
+
- `DatabaseEntryRepository.ts`: SQLite/Postgres unique constraint violation translation to `EntryUniqueConflict`.
|
|
172
|
+
- `InvokeBuiltinUseCase.ts`: Matched upsert execution via `findByDataFields` and `projectUpdateAndStamp`.
|
|
173
|
+
- **`@aotter/mantle-indexeddb`**:
|
|
174
|
+
- `IndexedDbEntryRepository.ts`: Atomic transaction-level unique index enforcement and `EntryUniqueConflict` emission.
|
|
175
|
+
- **Documentation**:
|
|
176
|
+
- `docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md` (this document).
|
|
177
|
+
- `docs/adr/README.md`.
|
|
178
|
+
- `docs/design-atoms.md`.
|
package/docs/adr/README.md
CHANGED
|
@@ -20,6 +20,7 @@ Records of *why* mantle ended up shaped this way. The numbering preserves POC AD
|
|
|
20
20
|
| [0017](0017-media-multi-variant-agent-side-optimization.md) | Multi-variant media assets with agent-side optimization and asset-id entry references. | Accepted |
|
|
21
21
|
| [0018](0018-core-starters-repository-boundary.md) | Core produces published SDK artifacts; the separate starters repository validates them as an external consumer. Revisit after release-contract simplification. | Accepted for now |
|
|
22
22
|
| [0019](0019-sealed-manifest-runtime-pipeline.md) | One sealed source-to-runtime pipeline, semantic storage seam, and optional Web/Admin/platform dependency direction. | Accepted |
|
|
23
|
+
| [0020](0020-builtin-handler-contracts-and-matched-upsert.md) | Static builtin handler contracts and natural-key matched upsert (`handler.match`). | Accepted |
|
|
23
24
|
|
|
24
25
|
## Reading order
|
|
25
26
|
|
package/docs/design-atoms.md
CHANGED
|
@@ -690,24 +690,27 @@ spec:
|
|
|
690
690
|
kind: builtin
|
|
691
691
|
op: create | update | upsert | delete | archive
|
|
692
692
|
schema: <Schema metadata.name>
|
|
693
|
+
match: [ <field>, ... ] # optional; only valid for op: upsert
|
|
693
694
|
```
|
|
694
695
|
|
|
695
|
-
| op | Behavior |
|
|
696
|
-
|
|
697
|
-
| `create` | INSERT a new row. Project `input ∩ Schema.spec.schema.properties`; stamp `x-mantle-bind` fields; generated id; status is `draft`, or immediately `published` for `lifecycle: operational`. |
|
|
698
|
-
| `update` | UPDATE in place. `input.id`
|
|
699
|
-
| `upsert` | If `input.id` resolves,
|
|
700
|
-
| `delete` | Hard DELETE by id. |
|
|
701
|
-
| `archive` | Soft-archive a publishing entry (`status='archived'`). |
|
|
696
|
+
| op | Behavior | Input Contract Requirements |
|
|
697
|
+
|---|---|---|
|
|
698
|
+
| `create` | INSERT a new row. Project `input ∩ Schema.spec.schema.properties`; stamp `x-mantle-bind` fields; generated id; status is `draft`, or immediately `published` for `lifecycle: operational`. | `input` must be an object schema. |
|
|
699
|
+
| `update` | UPDATE in place. Merges patch with existing data via `projectUpdateAndStamp`. Bumps version. | `input.id` (strict string) and `input.expectedVersion` (strict number) are required in `input.required`. |
|
|
700
|
+
| `upsert` | If `match` is declared, queries by matched natural key fields: if found, updates the row via `projectUpdateAndStamp` using the row's existing version; if not found, creates a new row. If `match` is omitted (legacy), updates when `input.id` resolves, else creates. | If `match` is set, matched fields must match a declared unique index on the Schema, be declared in `input.properties`, and appear in `input.required`; `id` and `expectedVersion` must NOT be in `input`. If `match` is omitted and `id` or `expectedVersion` is declared, both must be declared with strict string/number types. |
|
|
701
|
+
| `delete` | Hard DELETE by id. | `input.id` (strict string) is required in `input.required`. |
|
|
702
|
+
| `archive` | Soft-archive a publishing entry (`status='archived'`). | Valid only on Schemas with `lifecycle: publishing`. `input.id` (strict string) is required in `input.required`. |
|
|
702
703
|
|
|
703
704
|
The Procedure's `input` is the contract with the *caller*. It MAY
|
|
704
705
|
declare fields the Schema does not (e.g. a Turnstile token). The
|
|
705
706
|
builtin op silently projects `input ∩ Schema.properties` and ignores
|
|
706
707
|
the rest; JSON Schema's default `additionalProperties: true` lets
|
|
707
708
|
the side-channel fields pass validation. To act on those fields
|
|
708
|
-
(read the token, call the vendor), declare a `before_create`
|
|
709
|
+
(read the token, call the vendor), declare a `before_create` or `before_update`
|
|
709
710
|
lifecycle Trigger — see below.
|
|
710
711
|
|
|
712
|
+
Under concurrent execution, database-level unique constraints catch any race conditions where concurrent writers miss preflight lookup, surfacing as standard `CONFLICT` diagnostics (HTTP 409) without automatic retries.
|
|
713
|
+
|
|
711
714
|
`request_publish` and `publish` are intentionally not in the builtin
|
|
712
715
|
vocabulary. They are lifecycle operations, not CRUD primitives.
|
|
713
716
|
|
package/docs/release-process.md
CHANGED
|
@@ -121,17 +121,18 @@ gh api --method POST repos/aotter/mantle/releases/generate-notes \
|
|
|
121
121
|
--jq .body
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
The
|
|
124
|
+
The ten public packages publish in dependency order:
|
|
125
125
|
|
|
126
126
|
1. `@aotter/mantle-spec`
|
|
127
127
|
2. `@aotter/mantle-admin-ui`
|
|
128
128
|
3. `@aotter/mantle-runtime`
|
|
129
|
-
4. `@aotter/mantle-
|
|
130
|
-
5. `@aotter/mantle-
|
|
131
|
-
6. `@aotter/mantle-
|
|
132
|
-
7. `@aotter/mantle-
|
|
133
|
-
8. `@aotter/mantle-
|
|
134
|
-
9. `@aotter/mantle`
|
|
129
|
+
4. `@aotter/mantle-indexeddb`
|
|
130
|
+
5. `@aotter/mantle-web`
|
|
131
|
+
6. `@aotter/mantle-admin`
|
|
132
|
+
7. `@aotter/mantle-bun`
|
|
133
|
+
8. `@aotter/mantle-vercel`
|
|
134
|
+
9. `@aotter/mantle-cloudflare`
|
|
135
|
+
10. `@aotter/mantle`
|
|
135
136
|
|
|
136
137
|
The umbrella package must contain its version-matched `docs/` and `skills/`
|
|
137
138
|
payload. No tarball may contain `workspace:*` dependencies, secrets, local
|
|
@@ -156,7 +157,7 @@ Before creating the Core tag, the controller proves:
|
|
|
156
157
|
- the requested version matches every package, plugin, and marketplace ref;
|
|
157
158
|
- `pnpm check` passes;
|
|
158
159
|
- packed Core passes in the exact pinned Starter source;
|
|
159
|
-
- all
|
|
160
|
+
- all ten release tarballs exist;
|
|
160
161
|
- npm and cross-repository credentials are present and readable;
|
|
161
162
|
- a fresh version is unused across npmjs, GitHub Packages, and Starter tags;
|
|
162
163
|
- the pinned Starter commit is still the remote `develop` tip.
|
|
@@ -194,7 +195,7 @@ Core repository secrets:
|
|
|
194
195
|
|
|
195
196
|
| Secret | Minimum purpose |
|
|
196
197
|
|---|---|
|
|
197
|
-
| `NPM_TOKEN` | Publish the
|
|
198
|
+
| `NPM_TOKEN` | Publish the ten `@aotter/*` packages on npmjs. |
|
|
198
199
|
| `RELEASE_FANOUT_TOKEN` | Read and dispatch `aotter/mantle-starters`; also read and dispatch `aotter/mantle-landing` only when Landing is enabled. |
|
|
199
200
|
|
|
200
201
|
Core's job-scoped `GITHUB_TOKEN` creates the Core tag and release and mirrors
|
|
@@ -217,6 +218,7 @@ for p in \
|
|
|
217
218
|
@aotter/mantle-spec \
|
|
218
219
|
@aotter/mantle-admin-ui \
|
|
219
220
|
@aotter/mantle-runtime \
|
|
221
|
+
@aotter/mantle-indexeddb \
|
|
220
222
|
@aotter/mantle-web \
|
|
221
223
|
@aotter/mantle-admin \
|
|
222
224
|
@aotter/mantle-bun \
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aotter/mantle",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.15",
|
|
4
4
|
"description": "Embeddable Mantle Core umbrella with Spec and Runtime; Web, Admin, Bun, Vercel, Cloudflare, and Admin UI are optional peer packages.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://mantle.tools/",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"README.md"
|
|
84
84
|
],
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@aotter/mantle-runtime": "0.1.0-alpha.
|
|
87
|
-
"@aotter/mantle-spec": "0.1.0-alpha.
|
|
86
|
+
"@aotter/mantle-runtime": "0.1.0-alpha.15",
|
|
87
|
+
"@aotter/mantle-spec": "0.1.0-alpha.15"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
90
|
"aws4fetch": "^1.0.20",
|
|
@@ -92,12 +92,12 @@
|
|
|
92
92
|
"hono": "^4.12.0",
|
|
93
93
|
"@libsql/client": "^0.17.4",
|
|
94
94
|
"zod": "^4.5.0",
|
|
95
|
-
"@aotter/mantle-
|
|
96
|
-
"@aotter/mantle-admin-ui": "0.1.0-alpha.
|
|
97
|
-
"@aotter/mantle-
|
|
98
|
-
"@aotter/mantle-
|
|
99
|
-
"@aotter/mantle-web": "0.1.0-alpha.
|
|
100
|
-
"@aotter/mantle-vercel": "0.1.0-alpha.
|
|
95
|
+
"@aotter/mantle-bun": "0.1.0-alpha.15",
|
|
96
|
+
"@aotter/mantle-admin-ui": "0.1.0-alpha.15",
|
|
97
|
+
"@aotter/mantle-cloudflare": "0.1.0-alpha.15",
|
|
98
|
+
"@aotter/mantle-admin": "0.1.0-alpha.15",
|
|
99
|
+
"@aotter/mantle-web": "0.1.0-alpha.15",
|
|
100
|
+
"@aotter/mantle-vercel": "0.1.0-alpha.15"
|
|
101
101
|
},
|
|
102
102
|
"peerDependenciesMeta": {
|
|
103
103
|
"@aotter/mantle-admin": {
|
|
@@ -135,17 +135,17 @@
|
|
|
135
135
|
"@types/node": "^26",
|
|
136
136
|
"aws4fetch": "^1.0.20",
|
|
137
137
|
"better-auth": "^1.7.1",
|
|
138
|
-
"hono": "^4.13.
|
|
138
|
+
"hono": "^4.13.3",
|
|
139
139
|
"@libsql/client": "^0.17.4",
|
|
140
140
|
"typescript": "^6.0.3",
|
|
141
|
-
"vitest": "^4.1.
|
|
141
|
+
"vitest": "^4.1.11",
|
|
142
142
|
"zod": "^4.5.4",
|
|
143
|
-
"@aotter/mantle-admin
|
|
144
|
-
"@aotter/mantle-
|
|
145
|
-
"@aotter/mantle-cloudflare": "0.1.0-alpha.
|
|
146
|
-
"@aotter/mantle-
|
|
147
|
-
"@aotter/mantle-vercel": "0.1.0-alpha.
|
|
148
|
-
"@aotter/mantle-web": "0.1.0-alpha.
|
|
143
|
+
"@aotter/mantle-admin": "0.1.0-alpha.15",
|
|
144
|
+
"@aotter/mantle-admin-ui": "0.1.0-alpha.15",
|
|
145
|
+
"@aotter/mantle-cloudflare": "0.1.0-alpha.15",
|
|
146
|
+
"@aotter/mantle-bun": "0.1.0-alpha.15",
|
|
147
|
+
"@aotter/mantle-vercel": "0.1.0-alpha.15",
|
|
148
|
+
"@aotter/mantle-web": "0.1.0-alpha.15"
|
|
149
149
|
},
|
|
150
150
|
"engines": {
|
|
151
151
|
"node": ">=22"
|