@saacms/core 0.1.0
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 +25 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/access/index.d.ts +37 -0
- package/dist/access/index.d.ts.map +1 -0
- package/dist/access/index.js +6 -0
- package/dist/auth/index.d.ts +30 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/codegen/content-migration.d.ts +167 -0
- package/dist/codegen/content-migration.d.ts.map +1 -0
- package/dist/codegen/filter-openapi-for-user.d.ts +100 -0
- package/dist/codegen/filter-openapi-for-user.d.ts.map +1 -0
- package/dist/codegen/index.d.ts +19 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +43 -0
- package/dist/codegen/openapi-types.d.ts +125 -0
- package/dist/codegen/openapi-types.d.ts.map +1 -0
- package/dist/codegen/to-d1-migration.d.ts +88 -0
- package/dist/codegen/to-d1-migration.d.ts.map +1 -0
- package/dist/codegen/to-drizzle.d.ts +131 -0
- package/dist/codegen/to-drizzle.d.ts.map +1 -0
- package/dist/codegen/to-openapi.d.ts +80 -0
- package/dist/codegen/to-openapi.d.ts.map +1 -0
- package/dist/codegen/to-puck-fields.d.ts +109 -0
- package/dist/codegen/to-puck-fields.d.ts.map +1 -0
- package/dist/codegen/to-ts-types.d.ts +59 -0
- package/dist/codegen/to-ts-types.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +94 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +8 -0
- package/dist/host/index.d.ts +109 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +16 -0
- package/dist/index-172n82sz.js +4 -0
- package/dist/index-8g8ymd37.js +275 -0
- package/dist/index-a3pnt8yz.js +1494 -0
- package/dist/index-b59hfany.js +3078 -0
- package/dist/index-b7z43xwp.js +6 -0
- package/dist/index-r0at8zaw.js +13 -0
- package/dist/index-zgbq60fy.js +74 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +261 -0
- package/dist/observability/audit.d.ts +65 -0
- package/dist/observability/audit.d.ts.map +1 -0
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/publish/compile.d.ts +76 -0
- package/dist/publish/compile.d.ts.map +1 -0
- package/dist/runtime/auth-middleware.d.ts +34 -0
- package/dist/runtime/auth-middleware.d.ts.map +1 -0
- package/dist/runtime/boolean-columns.d.ts +65 -0
- package/dist/runtime/boolean-columns.d.ts.map +1 -0
- package/dist/runtime/cache.d.ts +62 -0
- package/dist/runtime/cache.d.ts.map +1 -0
- package/dist/runtime/create-route.d.ts +26 -0
- package/dist/runtime/create-route.d.ts.map +1 -0
- package/dist/runtime/delete-route.d.ts +15 -0
- package/dist/runtime/delete-route.d.ts.map +1 -0
- package/dist/runtime/drafts-route.d.ts +65 -0
- package/dist/runtime/drafts-route.d.ts.map +1 -0
- package/dist/runtime/health-route.d.ts +23 -0
- package/dist/runtime/health-route.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +24 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +17 -0
- package/dist/runtime/json-columns.d.ts +50 -0
- package/dist/runtime/json-columns.d.ts.map +1 -0
- package/dist/runtime/list-route.d.ts +20 -0
- package/dist/runtime/list-route.d.ts.map +1 -0
- package/dist/runtime/openapi-route.d.ts +30 -0
- package/dist/runtime/openapi-route.d.ts.map +1 -0
- package/dist/runtime/pattern-route.d.ts +48 -0
- package/dist/runtime/pattern-route.d.ts.map +1 -0
- package/dist/runtime/problem-details.d.ts +32 -0
- package/dist/runtime/problem-details.d.ts.map +1 -0
- package/dist/runtime/put-route.d.ts +19 -0
- package/dist/runtime/put-route.d.ts.map +1 -0
- package/dist/runtime/read-route.d.ts +26 -0
- package/dist/runtime/read-route.d.ts.map +1 -0
- package/dist/runtime/scale-cost.d.ts +84 -0
- package/dist/runtime/scale-cost.d.ts.map +1 -0
- package/dist/runtime/scheme-route.d.ts +49 -0
- package/dist/runtime/scheme-route.d.ts.map +1 -0
- package/dist/runtime/services.d.ts +42 -0
- package/dist/runtime/services.d.ts.map +1 -0
- package/dist/runtime/update-route.d.ts +20 -0
- package/dist/runtime/update-route.d.ts.map +1 -0
- package/dist/runtime/upload-route.d.ts +46 -0
- package/dist/runtime/upload-route.d.ts.map +1 -0
- package/dist/schema/index.d.ts +185 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +40 -0
- package/dist/schema/media.d.ts +237 -0
- package/dist/schema/media.d.ts.map +1 -0
- package/dist/schema/plugin-trust.d.ts +144 -0
- package/dist/schema/plugin-trust.d.ts.map +1 -0
- package/dist/signals/index.d.ts +10 -0
- package/dist/signals/index.d.ts.map +1 -0
- package/dist/signals/index.js +10 -0
- package/dist/storage/index.d.ts +120 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +13 -0
- package/dist/tenant/index.d.ts +105 -0
- package/dist/tenant/index.d.ts.map +1 -0
- package/dist/theme/index.d.ts +56 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/types/ids.d.ts +45 -0
- package/dist/types/ids.d.ts.map +1 -0
- package/dist/types/ids.js +15 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/user.d.ts +14 -0
- package/dist/types/user.d.ts.map +1 -0
- package/dist/types/user.js +1 -0
- package/package.json +116 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-d1-migration.d.ts","sourceRoot":"","sources":["../../src/codegen/to-d1-migration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAqFvD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAsBD,mGAAmG;AACnG,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASpD;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC,GAC1D,IAAI,CAgBN;AAED,KAAK,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;AA+E/C;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAqD/D;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAClC,MAAM,CAMR"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema → Drizzle table projection per ADR 0005 (Effect Schema is the single
|
|
3
|
+
* source of truth) and ADR 0024 (v1 alpha targets D1/SQLite, so we emit
|
|
4
|
+
* `drizzle-orm/sqlite-core` tables).
|
|
5
|
+
*
|
|
6
|
+
* One function:
|
|
7
|
+
* - `schemaToDrizzle(slug, schema)` — projects an Effect Schema struct to a
|
|
8
|
+
* Drizzle SQLite table with auto-injected `id`, `createdAt`, `updatedAt`.
|
|
9
|
+
*
|
|
10
|
+
* --------------------------------------------------------------------
|
|
11
|
+
* Annotation namespace (saacms-prefixed; mirrors `to-openapi.ts` convention)
|
|
12
|
+
* --------------------------------------------------------------------
|
|
13
|
+
*
|
|
14
|
+
* The following Effect-Schema annotations are recognised on per-property AST
|
|
15
|
+
* nodes (read with `.annotations({ ... })`). All keys are saacms-prefixed
|
|
16
|
+
* strings (per ADR 0005 §Consequences — "Annotation collision avoidance").
|
|
17
|
+
*
|
|
18
|
+
* `saacmsRef: <CollectionSlug>` — marks a `Schema.String` field as a foreign
|
|
19
|
+
* key to another Collection's `id` column. v1 emits a Drizzle `references`
|
|
20
|
+
* callback that resolves through an internal placeholder registry (the
|
|
21
|
+
* foreign Collection's table doesn't have to be in scope at projection
|
|
22
|
+
* time — the codegen-CLI assembler swaps the placeholder for the real
|
|
23
|
+
* table later). Cascading delete defaults to `cascade` per task spec
|
|
24
|
+
* (most natural for saacms); override later via a config knob if needed.
|
|
25
|
+
*
|
|
26
|
+
* `saacmsInt: true` — narrows a `Schema.Number` field from `real` (SQLite
|
|
27
|
+
* REAL / IEEE-754 double) to `integer`. Use when the field is logically
|
|
28
|
+
* an integer count (e.g. `views`, `priority`).
|
|
29
|
+
*
|
|
30
|
+
* `saacmsLength: number` — max length on a `Schema.String`. SQLite stores
|
|
31
|
+
* TEXT regardless, but Drizzle's text builder accepts a `length` config
|
|
32
|
+
* for dialect dialects that honour it; harmless on SQLite, useful when
|
|
33
|
+
* the same Schema is reprojected for postgres/mysql in v1.x.
|
|
34
|
+
*
|
|
35
|
+
* `saacmsRefOnDelete: "cascade" | "restrict" | "set null" | "no action"` —
|
|
36
|
+
* overrides the default `cascade` behaviour for a `saacmsRef` field.
|
|
37
|
+
*
|
|
38
|
+
* --------------------------------------------------------------------
|
|
39
|
+
* AST-walking decisions (callable out for review)
|
|
40
|
+
* --------------------------------------------------------------------
|
|
41
|
+
*
|
|
42
|
+
* 1. The root schema MUST be a `TypeLiteral` (i.e. `Schema.Struct({...})`).
|
|
43
|
+
* Suspended / refined / union root schemas throw — we want a single canonical
|
|
44
|
+
* table shape per Collection.
|
|
45
|
+
*
|
|
46
|
+
* 2. A field is treated as nullable (omit `.notNull()`) when EITHER
|
|
47
|
+
* a) the PropertySignature has `isOptional: true` (i.e. `key?:` in the
|
|
48
|
+
* encoded type), OR
|
|
49
|
+
* b) the property's type is a `Union` containing `UndefinedKeyword` or
|
|
50
|
+
* `NullKeyword`.
|
|
51
|
+
* Both are produced by `Schema.optional(X)` / `Schema.NullOr(X)`. We strip
|
|
52
|
+
* those wrappers to get the inner "data" type before mapping to a column.
|
|
53
|
+
*
|
|
54
|
+
* 3. `Refinement` wrappers (e.g. `Schema.String.pipe(Schema.minLength(1))`)
|
|
55
|
+
* are walked through — we look at `refinement.from` recursively until we
|
|
56
|
+
* hit a non-refinement. SQLite has no `CHECK length(x) >= 1` enforced by
|
|
57
|
+
* Drizzle's column builder; the validation lives in the Effect Schema and
|
|
58
|
+
* runs at the application boundary (per ADR 0005).
|
|
59
|
+
*
|
|
60
|
+
* 4. `Schema.Array(X)` becomes `text(name, { mode: "json" })` for v1. Dedicated
|
|
61
|
+
* junction tables (the structurally-correct projection) are deferred — JSON
|
|
62
|
+
* column is the pragmatic SQLite default and matches what every CMS that
|
|
63
|
+
* targets D1 ships today.
|
|
64
|
+
*
|
|
65
|
+
* 5. `Schema.Date` / `Schema.DateFromSelf` are detected by Effect's identifier
|
|
66
|
+
* annotation (`getIdentifierAnnotation(ast) === "DateFromSelf"`). Both
|
|
67
|
+
* project to `integer(name, { mode: "timestamp" })` — SQLite stores Unix
|
|
68
|
+
* seconds, Drizzle hydrates to JS `Date`.
|
|
69
|
+
*
|
|
70
|
+
* 6. Annotations are read off the inner data type's annotations (after
|
|
71
|
+
* union-stripping). `Schema.optional(Schema.String.annotations({saacmsRef: "x"}))`
|
|
72
|
+
* works; the annotation is on the String, not on the optional wrapper.
|
|
73
|
+
*
|
|
74
|
+
* 7. The synthetic `id`, `createdAt`, `updatedAt` columns are ALWAYS injected
|
|
75
|
+
* and override any user-defined columns of the same name. Logged in dev as
|
|
76
|
+
* a TODO when collision is detected (left for the codegen-CLI assembler).
|
|
77
|
+
*
|
|
78
|
+
* --------------------------------------------------------------------
|
|
79
|
+
* Foreign-key resolution (placeholder registry)
|
|
80
|
+
* --------------------------------------------------------------------
|
|
81
|
+
*
|
|
82
|
+
* Drizzle's `references(callback, actions)` takes a thunk returning a real
|
|
83
|
+
* `SQLiteColumn`. At projection time the foreign Collection's table object
|
|
84
|
+
* may not exist yet (chicken-and-egg when both Collections reference each
|
|
85
|
+
* other). We resolve this with a per-projection placeholder map:
|
|
86
|
+
*
|
|
87
|
+
* - First time we see `saacmsRef: "users"`, we synthesize a stub
|
|
88
|
+
* `usersPlaceholder = sqliteTable("users", { id: text("id").primaryKey() })`
|
|
89
|
+
* and cache it.
|
|
90
|
+
* - The reference thunk returns `usersPlaceholder.id`.
|
|
91
|
+
* - The codegen-CLI assembler (when it eventually merges all real tables)
|
|
92
|
+
* replaces placeholders with actual table refs. For v1 unit-test
|
|
93
|
+
* purposes, `getTableConfig(...).foreignKeys[i].reference()` returns a
|
|
94
|
+
* well-formed `{ foreignTable, foreignColumns }` shape with the right
|
|
95
|
+
* table NAME, which is what tests assert against.
|
|
96
|
+
*/
|
|
97
|
+
import type { Schema } from "effect";
|
|
98
|
+
/**
|
|
99
|
+
* Project an Effect Schema struct to a Drizzle SQLite table.
|
|
100
|
+
*
|
|
101
|
+
* Auto-injects `id` (text PK), `createdAt`, `updatedAt` (integer timestamps
|
|
102
|
+
* with default `() => new Date()`).
|
|
103
|
+
*
|
|
104
|
+
* @param slug — the Collection slug (also used as the table name)
|
|
105
|
+
* @param schema — an `effect/Schema` whose root is a `Schema.Struct({...})`
|
|
106
|
+
*/
|
|
107
|
+
export declare function schemaToDrizzle<TSchema extends Schema.Schema<any, any, any>>(slug: string, schema: TSchema): import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
108
|
+
name: string;
|
|
109
|
+
schema: undefined;
|
|
110
|
+
columns: {
|
|
111
|
+
[x: string]: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
112
|
+
name: string;
|
|
113
|
+
tableName: string;
|
|
114
|
+
dataType: import("drizzle-orm").ColumnDataType;
|
|
115
|
+
columnType: string;
|
|
116
|
+
data: unknown;
|
|
117
|
+
driverParam: unknown;
|
|
118
|
+
notNull: false;
|
|
119
|
+
hasDefault: false;
|
|
120
|
+
isPrimaryKey: false;
|
|
121
|
+
isAutoincrement: false;
|
|
122
|
+
hasRuntimeDefault: false;
|
|
123
|
+
enumValues: string[] | undefined;
|
|
124
|
+
baseColumn: never;
|
|
125
|
+
identity: undefined;
|
|
126
|
+
generated: undefined;
|
|
127
|
+
}, object>;
|
|
128
|
+
};
|
|
129
|
+
dialect: "sqlite";
|
|
130
|
+
}>;
|
|
131
|
+
//# sourceMappingURL=to-drizzle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-drizzle.d.ts","sourceRoot":"","sources":["../../src/codegen/to-drizzle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+FG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAsLpC;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAC1E,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;GAuChB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema → OpenAPI projections per ADR 0005 (Schema is the source) and
|
|
3
|
+
* ADR 0018 (the API design contract every endpoint follows).
|
|
4
|
+
*
|
|
5
|
+
* Two functions:
|
|
6
|
+
* - `schemaToOpenApiSchema(schema)` — projects an Effect Schema to an
|
|
7
|
+
* OpenAPI 3.1 Schema Object (also a JSON Schema 2020-12 document, since
|
|
8
|
+
* OAS 3.1 aligns with that JSON Schema dialect).
|
|
9
|
+
* - `collectionToOpenApiPaths(coll, opts?)` — emits the canonical CRUD path
|
|
10
|
+
* set for a Collection, ETag/Idempotency-Key/If-Match conventions,
|
|
11
|
+
* Problem Details error responses, and tags.
|
|
12
|
+
*
|
|
13
|
+
* Implementation notes (edge-case decisions made here, callable out for review):
|
|
14
|
+
*
|
|
15
|
+
* 1. We pass `target: "openApi3.1"` to Effect's `JSONSchema.make`. That dialect
|
|
16
|
+
* aligns with JSON Schema 2020-12 (OAS 3.1's chosen dialect — see OAS 3.1
|
|
17
|
+
* §4.7.24.5), so the output is already OpenAPI-shaped: it uses
|
|
18
|
+
* `type: ["string","null"]` arrays for nullable rather than the OAS 3.0
|
|
19
|
+
* `nullable: true` keyword. We do NOT post-translate to 3.0; we target 3.1.
|
|
20
|
+
*
|
|
21
|
+
* 2. Effect Schema annotation surfacing: we walk the AST and, for each
|
|
22
|
+
* PropertySignature, read three saacms-namespaced annotations (`saacmsLabel`,
|
|
23
|
+
* `saacmsHelp`, `saacmsFormat`) plus the standard Effect annotations
|
|
24
|
+
* (`title`, `description`, `examples`). We project them onto the matching
|
|
25
|
+
* `properties[name]` slot in the emitted Schema Object. `saacmsLabel` wins
|
|
26
|
+
* over `title` for `description` (it's the human label intended for forms);
|
|
27
|
+
* `saacmsHelp` falls back to existing `description`; `saacmsFormat` overrides
|
|
28
|
+
* `format`.
|
|
29
|
+
*
|
|
30
|
+
* 3. `cookieAuth` and `bearerAuth` security schemes are *referenced* on every
|
|
31
|
+
* operation; their `components.securitySchemes` definitions are NOT emitted
|
|
32
|
+
* here. The runtime layer that assembles the full OpenAPI document attaches
|
|
33
|
+
* those scheme definitions (Better Auth cookie + JWT bearer per ADR 0008).
|
|
34
|
+
* TODO(runtime-assembler): wire securitySchemes when ADR 0008 lands.
|
|
35
|
+
*
|
|
36
|
+
* 4. Per ADR 0006, this generator emits the FULL spec for the Collection (every
|
|
37
|
+
* field, every verb). The runtime layer that returns `/api/openapi.json` per
|
|
38
|
+
* user calls into this output and then prunes routes/fields the user can't
|
|
39
|
+
* reach. The pruning is intentionally NOT done here so this projection stays
|
|
40
|
+
* a pure function of the Schema and CollectionDef (deterministic, cacheable,
|
|
41
|
+
* snapshot-testable).
|
|
42
|
+
*
|
|
43
|
+
* 5. Tag policy: one tag per Collection, equal to the Collection slug. Lets
|
|
44
|
+
* typed-client generators (`openapi-typescript`, `orval`, etc.) group SDK
|
|
45
|
+
* methods by Collection.
|
|
46
|
+
*/
|
|
47
|
+
import { Schema } from "effect";
|
|
48
|
+
import type { CollectionDef, AnySchema } from "../schema/index.ts";
|
|
49
|
+
import type { OpenAPIPathsObject, OpenAPISchemaObject } from "./openapi-types.ts";
|
|
50
|
+
/**
|
|
51
|
+
* Pure pre-pass: returns a Schema equivalent to `schema` except every
|
|
52
|
+
* date-class field projects to `{ type: "string", format: "date-time" }`
|
|
53
|
+
* under `JSONSchema.make`. General over property path (top-level, nested
|
|
54
|
+
* struct, array items, union members, optional fields). Idempotent.
|
|
55
|
+
*/
|
|
56
|
+
export declare function normalizeDateSchemas(schema: Schema.Schema<any, any, any>): Schema.Schema<any, any, any>;
|
|
57
|
+
/**
|
|
58
|
+
* Project an Effect Schema to an OpenAPI 3.1 Schema Object.
|
|
59
|
+
*
|
|
60
|
+
* Uses Effect's first-class JSON Schema export (`JSONSchema.make` with
|
|
61
|
+
* `target: "openApi3.1"`) and post-processes per-property to surface saacms
|
|
62
|
+
* UI annotations (label / help text / format) into OpenAPI fields.
|
|
63
|
+
*
|
|
64
|
+
* Date-class fields are normalized to the canonical RFC 3339 date-time string
|
|
65
|
+
* form first (see `normalizeDateSchemas`) so the projection is total for any
|
|
66
|
+
* valid schema per ADR 0005.
|
|
67
|
+
*/
|
|
68
|
+
export declare function schemaToOpenApiSchema(schema: Schema.Schema<any, any, any>): OpenAPISchemaObject;
|
|
69
|
+
export interface CollectionToOpenApiPathsOptions {
|
|
70
|
+
/** Per ADR 0018 §13 — defaults to `/api/saacms/v1`. */
|
|
71
|
+
readonly basePath?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface CollectionToOpenApiPathsResult {
|
|
74
|
+
readonly paths: OpenAPIPathsObject;
|
|
75
|
+
readonly components: {
|
|
76
|
+
readonly schemas: Record<string, OpenAPISchemaObject>;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export declare function collectionToOpenApiPaths(coll: CollectionDef<AnySchema>, opts?: CollectionToOpenApiPathsOptions): CollectionToOpenApiPathsResult;
|
|
80
|
+
//# sourceMappingURL=to-openapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-openapi.d.ts","sourceRoot":"","sources":["../../src/codegen/to-openapi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAc,MAAM,EAAa,MAAM,QAAQ,CAAA;AAEtD,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,KAAK,EAEV,kBAAkB,EAKlB,mBAAmB,EAEpB,MAAM,oBAAoB,CAAA;AA4Q3B;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GACnC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAE9B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GACnC,mBAAmB,CAUrB;AA8GD,MAAM,WAAW,+BAA+B;IAC9C,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;IAClC,QAAQ,CAAC,UAAU,EAAE;QACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;KACtD,CAAA;CACF;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,aAAa,CAAC,SAAS,CAAC,EAC9B,IAAI,GAAE,+BAAoC,GACzC,8BAA8B,CA+ChC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema → Puck field-config projection per ADR 0011 (the visual editor renders
|
|
3
|
+
* fields off a Puck `fields` config object generated at build time from the
|
|
4
|
+
* Effect Schema). One function:
|
|
5
|
+
*
|
|
6
|
+
* - `schemaToPuckFields(coll)` — walks the Collection's root Struct and
|
|
7
|
+
* returns a `{ <fieldName>: PuckField }` map.
|
|
8
|
+
*
|
|
9
|
+
* --------------------------------------------------------------------
|
|
10
|
+
* Annotation namespace (saacms-prefixed; mirrors `to-drizzle.ts` convention)
|
|
11
|
+
* --------------------------------------------------------------------
|
|
12
|
+
*
|
|
13
|
+
* Recognised on the per-property data-type AST node (read with
|
|
14
|
+
* `.annotations({ ... })` on the inner Schema):
|
|
15
|
+
*
|
|
16
|
+
* `saacmsLabel: string` — UI label override; otherwise the camelCase JS
|
|
17
|
+
* name is converted to Title Case (`publishedAt` → `Published At`).
|
|
18
|
+
*
|
|
19
|
+
* `saacmsMultiline: true` — narrows a `Schema.String` field from `text` to
|
|
20
|
+
* `textarea` in the Puck UI.
|
|
21
|
+
*
|
|
22
|
+
* `saacmsRadio: true` — switches a `Schema.Literal(...)` string-literal
|
|
23
|
+
* union from the default `select` to a `radio` field in the Puck UI.
|
|
24
|
+
*
|
|
25
|
+
* --------------------------------------------------------------------
|
|
26
|
+
* AST-walking decisions
|
|
27
|
+
* --------------------------------------------------------------------
|
|
28
|
+
*
|
|
29
|
+
* 1. The root schema MUST be a `TypeLiteral` (i.e. `Schema.Struct({...})`).
|
|
30
|
+
* Suspended / refined / union root schemas throw — Puck's `fields` config
|
|
31
|
+
* is shaped as a flat keyed map and presupposes a struct.
|
|
32
|
+
*
|
|
33
|
+
* 2. `Schema.optional(X)` and `Schema.Union(X, undefined|null)` are peeled
|
|
34
|
+
* when the only remaining non-nullable member is a single type. A
|
|
35
|
+
* string-literal union (`Literal("a") | Literal("b")`) is preserved as-is
|
|
36
|
+
* so the select/radio detection sees the full member set.
|
|
37
|
+
*
|
|
38
|
+
* Optionality is currently INVISIBLE to Puck at this layer per the brief —
|
|
39
|
+
* Puck treats every field as optional UI-wise; the Effect Schema enforces
|
|
40
|
+
* required-ness server-side on PUT/POST. So no marker is emitted.
|
|
41
|
+
*
|
|
42
|
+
* 3. `Refinement` wrappers (e.g. `Schema.minLength(1)`) are walked through —
|
|
43
|
+
* we look at `refinement.from` recursively until we hit a non-refinement.
|
|
44
|
+
* Puck has no constraint-validation hook at the field-config layer; the
|
|
45
|
+
* refinement still runs server-side via the Schema.
|
|
46
|
+
*
|
|
47
|
+
* 4. `Schema.Array(Schema.Struct({...}))` becomes `{ type: "array", arrayFields }`.
|
|
48
|
+
* `Schema.Array(scalar)` falls back to `{ type: "text" }` — Puck's array
|
|
49
|
+
* field requires sub-`fields` (record-shaped), and a primitive-array UI
|
|
50
|
+
* is deferred to v1.x.
|
|
51
|
+
*
|
|
52
|
+
* 5. Annotations live on the inner data-type node after union- and
|
|
53
|
+
* refinement-stripping. `Schema.optional(Schema.String.annotations({...}))`
|
|
54
|
+
* works identically to a non-optional annotated string.
|
|
55
|
+
*
|
|
56
|
+
* 6. Anything we don't recognise (union of non-literal types, arbitrary
|
|
57
|
+
* transformations, …) falls back to `{ type: "text" }`. The codegen-CLI
|
|
58
|
+
* surfaces this as a warning at build time.
|
|
59
|
+
*/
|
|
60
|
+
import type { CollectionDef } from "../schema/index.ts";
|
|
61
|
+
export interface PuckFields {
|
|
62
|
+
readonly [name: string]: PuckField;
|
|
63
|
+
}
|
|
64
|
+
export type PuckField = {
|
|
65
|
+
readonly type: "text";
|
|
66
|
+
readonly label?: string;
|
|
67
|
+
} | {
|
|
68
|
+
readonly type: "textarea";
|
|
69
|
+
readonly label?: string;
|
|
70
|
+
} | {
|
|
71
|
+
readonly type: "number";
|
|
72
|
+
readonly label?: string;
|
|
73
|
+
} | {
|
|
74
|
+
readonly type: "select";
|
|
75
|
+
readonly label?: string;
|
|
76
|
+
readonly options: ReadonlyArray<{
|
|
77
|
+
readonly label: string;
|
|
78
|
+
readonly value: string;
|
|
79
|
+
}>;
|
|
80
|
+
} | {
|
|
81
|
+
readonly type: "radio";
|
|
82
|
+
readonly label?: string;
|
|
83
|
+
readonly options: ReadonlyArray<{
|
|
84
|
+
readonly label: string;
|
|
85
|
+
readonly value: string;
|
|
86
|
+
}>;
|
|
87
|
+
} | {
|
|
88
|
+
readonly type: "array";
|
|
89
|
+
readonly label?: string;
|
|
90
|
+
readonly arrayFields: PuckFields;
|
|
91
|
+
} | {
|
|
92
|
+
readonly type: "object";
|
|
93
|
+
readonly label?: string;
|
|
94
|
+
readonly objectFields: PuckFields;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* camelCase → "Camel Case". Splits on uppercase letters, capitalizes the
|
|
98
|
+
* first letter of each token. `"title"` → `"Title"`, `"publishedAt"` →
|
|
99
|
+
* `"Published At"`.
|
|
100
|
+
*/
|
|
101
|
+
export declare function defaultLabel(jsName: string): string;
|
|
102
|
+
/**
|
|
103
|
+
* Project a Collection's Effect Schema struct to a Puck `fields` config.
|
|
104
|
+
*
|
|
105
|
+
* Returns a `{ <fieldName>: PuckField }` map keyed by the JS property name
|
|
106
|
+
* (camelCase), one entry per top-level property of the root struct.
|
|
107
|
+
*/
|
|
108
|
+
export declare function schemaToPuckFields(coll: CollectionDef): PuckFields;
|
|
109
|
+
//# sourceMappingURL=to-puck-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-puck-fields.d.ts","sourceRoot":"","sources":["../../src/codegen/to-puck-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAMvD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,MAAM,MAAM,SAAS,GACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACpF,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACpF,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAA;CAAE,GACrF;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAA;CAAE,CAAA;AAwE3F;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOnD;AAkGD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,UAAU,CAWlE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema → TypeScript client-types projection per ADR 0005 (Effect Schema is
|
|
3
|
+
* the single source of truth). Two functions:
|
|
4
|
+
*
|
|
5
|
+
* - `schemaToTsType(coll)` — projects ONE Collection's root Struct to an
|
|
6
|
+
* `export interface <PascalCaseSlug> { ... }` source string.
|
|
7
|
+
* - `schemaToTsTypes(colls)` — joins many with a blank line, prefixed once
|
|
8
|
+
* by a `// generated by saacms — do not edit` header.
|
|
9
|
+
*
|
|
10
|
+
* This is the hand-editable client-types artefact `saacms codegen` writes to
|
|
11
|
+
* `.saacms/types/<slug>.ts`. It agrees with `to-drizzle.ts` /
|
|
12
|
+
* `to-d1-migration.ts` on field names, auto-injected columns, and the order
|
|
13
|
+
* convention (id first, user fields in declared order, createdAt/updatedAt
|
|
14
|
+
* last).
|
|
15
|
+
*
|
|
16
|
+
* --------------------------------------------------------------------
|
|
17
|
+
* Annotation namespace (saacms-prefixed; mirrors `to-d1-migration.ts`)
|
|
18
|
+
* --------------------------------------------------------------------
|
|
19
|
+
*
|
|
20
|
+
* `saacmsTsName: string` — override the emitted TS property name (rare;
|
|
21
|
+
* for when the DB column and the TS field intentionally differ, e.g. an
|
|
22
|
+
* `authorId` column surfaced as `authorRef` client-side). Read on the
|
|
23
|
+
* inner data-type node after optional/refinement stripping.
|
|
24
|
+
*
|
|
25
|
+
* --------------------------------------------------------------------
|
|
26
|
+
* Type mapping (Effect Schema → TS source)
|
|
27
|
+
* --------------------------------------------------------------------
|
|
28
|
+
*
|
|
29
|
+
* - `Schema.String` → `string`
|
|
30
|
+
* - `Schema.Number` → `number`
|
|
31
|
+
* - `Schema.Boolean` → `boolean`
|
|
32
|
+
* - `Schema.Literal("a","b")` → `"a" | "b"`
|
|
33
|
+
* - `Schema.Date` / DateFromString → `string` (ISO-8601)
|
|
34
|
+
* - `Schema.Array(X)` → `<TS-of-X>[]` (recurse)
|
|
35
|
+
* - nested `Schema.Struct({...})` → inline `{ a: string; b: number }`
|
|
36
|
+
* - `Schema.optional(X)` / Union(X,⊥) → optional KEY (`name?: <TS-of-X>`),
|
|
37
|
+
* never `| undefined` in the value
|
|
38
|
+
* - `Union(X, null)` → `<TS-of-X> | null` (key NOT optional)
|
|
39
|
+
* - unrecognised shape → `unknown` (graceful fallback; the
|
|
40
|
+
* codegen-CLI surfaces a warning)
|
|
41
|
+
*
|
|
42
|
+
* Refinements (`Schema.minLength` etc.) are unwrapped to their base type — TS
|
|
43
|
+
* has no refinement types; the constraint still runs server-side via Schema.
|
|
44
|
+
*/
|
|
45
|
+
import type { CollectionDef } from "../schema/index.ts";
|
|
46
|
+
/**
|
|
47
|
+
* Project a Collection's Effect Schema struct to an `export interface` source
|
|
48
|
+
* string. Auto-injected fields mirror `to-d1-migration.ts`: `id` first, then
|
|
49
|
+
* the user fields in declared order, then `createdAt` / `updatedAt` last (all
|
|
50
|
+
* ISO strings).
|
|
51
|
+
*/
|
|
52
|
+
export declare function schemaToTsType(coll: CollectionDef): string;
|
|
53
|
+
/**
|
|
54
|
+
* Project an ordered list of Collections to a single TS source file: one
|
|
55
|
+
* `// generated by saacms — do not edit` header, then each interface
|
|
56
|
+
* separated by a blank line.
|
|
57
|
+
*/
|
|
58
|
+
export declare function schemaToTsTypes(colls: ReadonlyArray<CollectionDef>): string;
|
|
59
|
+
//# sourceMappingURL=to-ts-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-ts-types.d.ts","sourceRoot":"","sources":["../../src/codegen/to-ts-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAuLvD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAyB1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAClC,MAAM,CAER"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effect-returning lifecycle hooks per ADR 0013.
|
|
3
|
+
*
|
|
4
|
+
* Hooks attach to Collections, Blocks, and Pages. Command-phase hooks (the
|
|
5
|
+
* `before*` family) can mutate data and cancel the operation via `Effect.fail`.
|
|
6
|
+
* Event-phase hooks (the `after*` family) run best-effort by default; failures
|
|
7
|
+
* are observable but non-blocking unless `failOnError` is set.
|
|
8
|
+
*/
|
|
9
|
+
import type { Schema } from "effect";
|
|
10
|
+
import { Effect } from "effect";
|
|
11
|
+
import type { User } from "../types/user.ts";
|
|
12
|
+
export type CollectionHookMoment = "beforeValidate" | "beforeChange" | "afterChange" | "beforeRead" | "afterRead" | "beforeDelete" | "afterDelete" | "beforePublish" | "afterPublish";
|
|
13
|
+
export type BlockHookMoment = "beforeRender" | "afterRender";
|
|
14
|
+
export type PageHookMoment = "beforePublish" | "afterPublish";
|
|
15
|
+
export type HookMoment = CollectionHookMoment | BlockHookMoment | PageHookMoment;
|
|
16
|
+
export type HookOp = "create" | "update" | "delete" | "read" | "publish" | "render";
|
|
17
|
+
/**
|
|
18
|
+
* Argument passed to every hook. Typed against the target Collection/Block schema
|
|
19
|
+
* so the inferred `data` / `record` properties carry the right shape.
|
|
20
|
+
*
|
|
21
|
+
* For command-phase hooks `data` is the proposed new state; for event-phase
|
|
22
|
+
* hooks `record` is the state after the operation succeeded.
|
|
23
|
+
*/
|
|
24
|
+
export interface HookContext<TSchema extends Schema.Schema<any, any, any>> {
|
|
25
|
+
readonly op: HookOp;
|
|
26
|
+
readonly user: User | null;
|
|
27
|
+
readonly data?: Schema.Schema.Type<TSchema>;
|
|
28
|
+
readonly record?: Schema.Schema.Type<TSchema>;
|
|
29
|
+
/** Free-form services container; populated by the runtime layer (Effect DI). */
|
|
30
|
+
readonly services?: Readonly<Record<string, unknown>>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A hook is an Effect-returning function. The `R` (requirements) channel may
|
|
34
|
+
* carry user-declared service tags resolved by the runtime layer; we leave it
|
|
35
|
+
* `unknown` at the type boundary so both DI-using and DI-free hooks fit.
|
|
36
|
+
*/
|
|
37
|
+
export type HookFn<TSchema extends Schema.Schema<any, any, any>> = (ctx: HookContext<TSchema>) => Effect.Effect<unknown, unknown, unknown>;
|
|
38
|
+
/**
|
|
39
|
+
* Per-hook configuration knobs (ADR 0013 §Shape).
|
|
40
|
+
* `failOnError` forces an `after*` hook to bubble failures to the caller.
|
|
41
|
+
* `queue` defers execution onto the platform queue (CF Queues / Vercel Queue).
|
|
42
|
+
*/
|
|
43
|
+
export interface HookOptions {
|
|
44
|
+
readonly failOnError?: boolean;
|
|
45
|
+
readonly queue?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/** A resolved hook entry: function plus optional per-hook configuration. */
|
|
48
|
+
export interface HookEntry<TSchema extends Schema.Schema<any, any, any>> {
|
|
49
|
+
readonly fn: HookFn<TSchema>;
|
|
50
|
+
readonly options?: HookOptions;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run the resolved chain of hooks for a `moment` against `ctx`.
|
|
54
|
+
*
|
|
55
|
+
* `hooks` is pre-resolved (already filtered to the right moment, already in
|
|
56
|
+
* user-then-plugin order per ADR 0014 conflict resolution). Use
|
|
57
|
+
* {@link resolveHooksFor} to derive it from a `SaacmsConfig` slice.
|
|
58
|
+
*
|
|
59
|
+
* Command-phase moments (`before*`) compose sequentially via `Effect.flatMap`:
|
|
60
|
+
* any failure short-circuits and propagates; each hook sees a `ctx` whose
|
|
61
|
+
* `data` is the previous hook's success value (when that value is a
|
|
62
|
+
* non-undefined object), else the data is left untouched.
|
|
63
|
+
*
|
|
64
|
+
* Event-phase moments (`after*`) compose in parallel via `Effect.all` with
|
|
65
|
+
* `concurrency: "unbounded"`. Failures are warned to the console under the
|
|
66
|
+
* `[saacms/hooks]` prefix unless the entry sets `options.failOnError === true`,
|
|
67
|
+
* in which case the failure propagates.
|
|
68
|
+
*
|
|
69
|
+
* `options.queue: true` is a v1.x platform-queue marker — documented here but
|
|
70
|
+
* a no-op for this dispatch; `@saacms/plugin-queues` will pick this up and
|
|
71
|
+
* lift the hook onto the host's queue (CF Queues / Vercel Queue) in v1.x.
|
|
72
|
+
*/
|
|
73
|
+
export declare function runHooks<TSchema extends Schema.Schema<any, any, any>>(moment: HookMoment, ctx: HookContext<TSchema>, hooks: ReadonlyArray<HookEntry<TSchema>>): Effect.Effect<unknown, unknown, unknown>;
|
|
74
|
+
/**
|
|
75
|
+
* Build the ordered hook chain for `moment` from a `SaacmsConfig` slice.
|
|
76
|
+
*
|
|
77
|
+
* Walks `source.collection.hooks[moment]` first, then each
|
|
78
|
+
* `source.plugins[i].hooks[moment]` in declaration order — matching ADR 0014
|
|
79
|
+
* §Conflict resolution (user wins, then plugins in listed order).
|
|
80
|
+
*
|
|
81
|
+
* Each `hooks[moment]` entry may be either a bare `HookFn` (wrapped as `{ fn }`)
|
|
82
|
+
* or a structured `{ fn, options? }` object. Anything else — strings, numbers,
|
|
83
|
+
* `undefined`, etc. — is silently skipped, since `hooks` is user-supplied data
|
|
84
|
+
* and a typo in a config file should not crash the runtime.
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveHooksFor<TSchema extends Schema.Schema<any, any, any>>(moment: HookMoment, source: {
|
|
87
|
+
readonly collection?: {
|
|
88
|
+
readonly hooks?: Record<string, unknown>;
|
|
89
|
+
};
|
|
90
|
+
readonly plugins?: ReadonlyArray<{
|
|
91
|
+
readonly hooks?: Record<string, unknown>;
|
|
92
|
+
}>;
|
|
93
|
+
}): ReadonlyArray<HookEntry<TSchema>>;
|
|
94
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host adapter interface per ADRs 0001 (compile step + runtime), 0003 (per-host
|
|
3
|
+
* adapter responsibilities), and 0004 (per-block preview routes).
|
|
4
|
+
*
|
|
5
|
+
* One host adapter exists per host framework (`@saacms/host-nextjs`,
|
|
6
|
+
* `@saacms/host-sveltekit`, `@saacms/host-nuxt`, `@saacms/host-astro`). Each
|
|
7
|
+
* knows three things and only three things:
|
|
8
|
+
*
|
|
9
|
+
* 1. how to *generate* native route files in the host's idiom (compile step),
|
|
10
|
+
* 2. how to *mount* the saacms runtime handler at the host's API location,
|
|
11
|
+
* 3. how to *emit* per-block preview routes the Puck canvas can fetch.
|
|
12
|
+
*
|
|
13
|
+
* This interface is the seam at the Hosting bounded context (ADR 0020).
|
|
14
|
+
* Everything above it is host-agnostic; everything below it is host-specific.
|
|
15
|
+
*/
|
|
16
|
+
import type { Hono } from "hono";
|
|
17
|
+
import type { PageDef, PageTemplateDef, BlockDef, RenderMode } from "../schema/index.ts";
|
|
18
|
+
/** Cookie names for the theme signal; constant so all host adapters are aligned. */
|
|
19
|
+
export declare const SCHEME_COOKIE: "saacms-scheme";
|
|
20
|
+
export declare const DARK_MODE_COOKIE: "saacms-dark";
|
|
21
|
+
/**
|
|
22
|
+
* No-FOUC theme-render contract (ADR 0033).
|
|
23
|
+
*
|
|
24
|
+
* A host adapter that supports themed SSR SHOULD implement this contract.
|
|
25
|
+
* saacms calls these methods during SSR to emit the active scheme's resolved
|
|
26
|
+
* token values into the initial document head before the body — zero flash,
|
|
27
|
+
* cache-correct.
|
|
28
|
+
*
|
|
29
|
+
* Contract only — concrete per-host emit is the named follow-up
|
|
30
|
+
* `theme-host-render`. An in-process conformance test proves correctness
|
|
31
|
+
* without a browser (same boundary discipline as the rest of the fleet).
|
|
32
|
+
*/
|
|
33
|
+
export interface ThemeRenderContract {
|
|
34
|
+
/**
|
|
35
|
+
* Read the active scheme ID and dark-mode preference from the request.
|
|
36
|
+
* Reads `saacms-scheme` (scheme ID) and `saacms-dark` ("1" = dark) cookies
|
|
37
|
+
* server-side. Returns `{ schemeId: null, darkMode: false }` when no cookies
|
|
38
|
+
* are set — zero JavaScript required; the server reads directly from headers.
|
|
39
|
+
*/
|
|
40
|
+
resolveActiveScheme(req: Request): {
|
|
41
|
+
schemeId: string | null;
|
|
42
|
+
darkMode: boolean;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Emit the scheme's resolved token values as an inline `<style>` block
|
|
46
|
+
* targeting `:root`. The returned HTML string is injected into the document
|
|
47
|
+
* `<head>` before any external stylesheets so cascade order is preserved.
|
|
48
|
+
*
|
|
49
|
+
* @param tokens — map of CSS custom-property name → value (without `--` prefix).
|
|
50
|
+
*/
|
|
51
|
+
emitThemeStyles(tokens: Record<string, string>): string;
|
|
52
|
+
/**
|
|
53
|
+
* Emit attribute markup for the document root element that identifies the
|
|
54
|
+
* active scheme and dark mode. Returns a string of HTML attributes
|
|
55
|
+
* (e.g. `data-theme="ocean" class="dark"`) to be placed on the `<html>` tag
|
|
56
|
+
* pre-body — the browser renders with the correct theme on the first paint.
|
|
57
|
+
*/
|
|
58
|
+
emitThemeAttribute(schemeId: string, darkMode: boolean): string;
|
|
59
|
+
}
|
|
60
|
+
export interface GeneratedRoute {
|
|
61
|
+
/** Repo-relative output path the host expects (e.g. `app/blog/[slug]/page.tsx`). */
|
|
62
|
+
readonly path: string;
|
|
63
|
+
readonly contents: string;
|
|
64
|
+
/** Per ADR 0021 — the cache emitter records mode metadata for cache wiring. */
|
|
65
|
+
readonly mode?: RenderMode;
|
|
66
|
+
}
|
|
67
|
+
export interface GenerateRouteContext {
|
|
68
|
+
readonly page: PageDef | PageTemplateDef;
|
|
69
|
+
/** When the page is a template, the bound Collection slug. */
|
|
70
|
+
readonly boundCollection?: string;
|
|
71
|
+
/** Repo-absolute path to the host's route root (`app/`, `src/routes/`, …). */
|
|
72
|
+
readonly routeRoot: string;
|
|
73
|
+
}
|
|
74
|
+
export interface GeneratePreviewRouteContext {
|
|
75
|
+
readonly block: BlockDef;
|
|
76
|
+
/** Repo-absolute path to the host's route root. */
|
|
77
|
+
readonly routeRoot: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Returned from `mountTemplate` so `saacms init` can write the right ~3-line
|
|
81
|
+
* mount file in the host's conventional location (e.g.
|
|
82
|
+
* `app/api/saacms/[...slug]/route.ts` for Next.js).
|
|
83
|
+
*/
|
|
84
|
+
export interface MountTemplate {
|
|
85
|
+
/** Repo-relative path of the mount file the host adapter expects. */
|
|
86
|
+
readonly path: string;
|
|
87
|
+
/** File contents — typically a tiny re-export of the runtime handler. */
|
|
88
|
+
readonly contents: string;
|
|
89
|
+
}
|
|
90
|
+
export interface HostAdapter {
|
|
91
|
+
readonly name: string;
|
|
92
|
+
/** Generate native route file(s) for a Page or Page template. */
|
|
93
|
+
generateRoute(ctx: GenerateRouteContext): ReadonlyArray<GeneratedRoute>;
|
|
94
|
+
/**
|
|
95
|
+
* Generate the per-Block preview route the Puck canvas fetches in dev mode
|
|
96
|
+
* (ADR 0004). Returns `null` if the block doesn't need a preview route
|
|
97
|
+
* (e.g. WC-mode blocks that render entirely client-side).
|
|
98
|
+
*/
|
|
99
|
+
generatePreviewRoute(ctx: GeneratePreviewRouteContext): GeneratedRoute | null;
|
|
100
|
+
/** Repo-relative directory the host serves static assets from (`public/` / `static/`). */
|
|
101
|
+
readonly assetRoot: string;
|
|
102
|
+
/**
|
|
103
|
+
* Returns the mount-file template `saacms init` writes into the host repo.
|
|
104
|
+
* Receives the runtime app so the adapter can decide whether to import it
|
|
105
|
+
* lazily, wrap it in framework-specific request adapters, etc.
|
|
106
|
+
*/
|
|
107
|
+
mountTemplate(runtime: Hono): MountTemplate;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAMxF,oFAAoF;AACpF,eAAO,MAAM,aAAa,EAAG,eAAwB,CAAA;AACrD,eAAO,MAAM,gBAAgB,EAAG,aAAsB,CAAA;AAEtD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;IAEjF;;;;;;OAMG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAA;IAEvD;;;;;OAKG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;CAChE;AAMD,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,eAAe,CAAA;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAA;IACxB,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAMD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAMD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,iEAAiE;IACjE,aAAa,CAAC,GAAG,EAAE,oBAAoB,GAAG,aAAa,CAAC,cAAc,CAAC,CAAA;IAEvE;;;;OAIG;IACH,oBAAoB,CAAC,GAAG,EAAE,2BAA2B,GAAG,cAAc,GAAG,IAAI,CAAA;IAE7E,0FAA0F;IAC1F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAE1B;;;;OAIG;IACH,aAAa,CAAC,OAAO,EAAE,IAAI,GAAG,aAAa,CAAA;CAC5C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host adapter interface per ADRs 0001 (compile step + runtime), 0003 (per-host
|
|
3
|
+
* adapter responsibilities), and 0004 (per-block preview routes).
|
|
4
|
+
*
|
|
5
|
+
* One host adapter exists per host framework (`@saacms/host-nextjs`,
|
|
6
|
+
* `@saacms/host-sveltekit`, `@saacms/host-nuxt`, `@saacms/host-astro`). Each
|
|
7
|
+
* knows three things and only three things:
|
|
8
|
+
*
|
|
9
|
+
* 1. how to *generate* native route files in the host's idiom (compile step),
|
|
10
|
+
* 2. how to *mount* the saacms runtime handler at the host's API location,
|
|
11
|
+
* 3. how to *emit* per-block preview routes the Puck canvas can fetch.
|
|
12
|
+
*
|
|
13
|
+
* This interface is the seam at the Hosting bounded context (ADR 0020).
|
|
14
|
+
* Everything above it is host-agnostic; everything below it is host-specific.
|
|
15
|
+
*/
|
|
16
|
+
export {};
|