@spacefast/common 0.2.1 → 0.4.1
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/dist/agents/marketplace-prompts.d.ts +1 -0
- package/dist/agents/marketplace-prompts.js +6 -0
- package/dist/agents/registry/core.d.ts +4 -12
- package/dist/agents/registry/core.js +7 -28
- package/dist/config/domains.d.ts +10 -8
- package/dist/config/domains.js +4 -7
- package/dist/contracts/access-core.d.ts +135 -0
- package/dist/contracts/access-core.js +242 -0
- package/dist/contracts/access-profiles.d.ts +8 -8
- package/dist/contracts/access-profiles.js +8 -8
- package/dist/contracts/access.d.ts +14 -103
- package/dist/contracts/access.js +10 -210
- package/dist/contracts/activity.d.ts +54 -55
- package/dist/contracts/activity.js +38 -9
- package/dist/contracts/api-keys.d.ts +69 -26
- package/dist/contracts/api-keys.js +29 -2
- package/dist/contracts/application-journal.d.ts +197 -4
- package/dist/contracts/application-journal.js +97 -16
- package/dist/contracts/auth.d.ts +20 -0
- package/dist/contracts/auth.js +18 -0
- package/dist/contracts/beta.d.ts +13 -0
- package/dist/contracts/beta.js +28 -0
- package/dist/contracts/billing.d.ts +2 -2
- package/dist/contracts/bootstrap.d.ts +23 -6
- package/dist/contracts/builds.d.ts +24 -4
- package/dist/contracts/builds.js +16 -4
- package/dist/contracts/channels.d.ts +43 -0
- package/dist/contracts/channels.js +22 -6
- package/dist/contracts/comments.d.ts +49 -0
- package/dist/contracts/comments.js +61 -2
- package/dist/contracts/commerce.d.ts +19 -13
- package/dist/contracts/connector-access.d.ts +28 -0
- package/dist/contracts/connector-access.js +31 -0
- package/dist/contracts/connectors.d.ts +2382 -0
- package/dist/contracts/connectors.js +941 -0
- package/dist/contracts/content-contract-verification.d.ts +112 -58
- package/dist/contracts/content-contract-verification.js +42 -54
- package/dist/contracts/content-model-emit.d.ts +97 -0
- package/dist/contracts/content-model-emit.js +306 -0
- package/dist/contracts/content-model-sdk.d.ts +101 -0
- package/dist/contracts/content-model-sdk.js +232 -0
- package/dist/contracts/{content-program.d.ts → content-model.d.ts} +338 -82
- package/dist/contracts/{content-program.js → content-model.js} +291 -63
- package/dist/contracts/content-platform-fixture.d.ts +380 -110
- package/dist/contracts/content-platform-fixture.js +8 -8
- package/dist/contracts/content-sync.d.ts +197 -74
- package/dist/contracts/content-sync.js +98 -37
- package/dist/contracts/content.d.ts +30 -422
- package/dist/contracts/content.js +34 -294
- package/dist/contracts/dashboard-prefs.d.ts +10 -3
- package/dist/contracts/dashboard-prefs.js +6 -3
- package/dist/contracts/data-location.d.ts +9 -0
- package/dist/contracts/data-location.js +7 -0
- package/dist/contracts/deployment-comparison.d.ts +67 -0
- package/dist/contracts/deployment-comparison.js +68 -0
- package/dist/contracts/device-auth.d.ts +55 -11
- package/dist/contracts/domains.d.ts +40 -16
- package/dist/contracts/domains.js +23 -0
- package/dist/contracts/enums.d.ts +1 -10
- package/dist/contracts/enums.js +0 -15
- package/dist/contracts/error-code-meta.d.ts +388 -20
- package/dist/contracts/error-code-meta.js +201 -5
- package/dist/contracts/error-codes.d.ts +17 -4
- package/dist/contracts/error-codes.js +109 -10
- package/dist/contracts/events.d.ts +5 -0
- package/dist/contracts/events.js +12 -3
- package/dist/contracts/execution.d.ts +5 -1
- package/dist/contracts/execution.js +4 -0
- package/dist/contracts/feature-lifecycle.d.ts +53 -20
- package/dist/contracts/feature-lifecycle.js +65 -23
- package/dist/contracts/features.d.ts +57 -31
- package/dist/contracts/features.js +0 -1
- package/dist/contracts/feedback.d.ts +124 -0
- package/dist/contracts/feedback.js +64 -0
- package/dist/contracts/fixtures/content-model-sdk-v1.generated.d.ts +129 -0
- package/dist/contracts/fixtures/content-model-sdk-v1.generated.js +48 -0
- package/dist/contracts/fixtures/content-platform-v1.json +101 -49
- package/dist/contracts/frame-session.d.ts +60 -10
- package/dist/contracts/frame-session.js +52 -12
- package/dist/contracts/functions.d.ts +28 -2
- package/dist/contracts/functions.js +25 -2
- package/dist/contracts/grant-copy.d.ts +2 -0
- package/dist/contracts/grant-copy.js +2 -0
- package/dist/contracts/grants-core.d.ts +95 -0
- package/dist/contracts/grants-core.js +435 -0
- package/dist/contracts/grants.d.ts +13 -84
- package/dist/contracts/grants.js +21 -369
- package/dist/contracts/ids-core.d.ts +11 -0
- package/dist/contracts/ids-core.js +14 -0
- package/dist/contracts/ids.d.ts +7 -4
- package/dist/contracts/ids.js +12 -4
- package/dist/contracts/internal.d.ts +18 -0
- package/dist/contracts/internal.js +19 -0
- package/dist/contracts/mcp.d.ts +8 -18
- package/dist/contracts/mcp.js +2 -23
- package/dist/contracts/notifications.d.ts +4 -1
- package/dist/contracts/notifications.js +1 -0
- package/dist/contracts/oauth-resources.d.ts +55 -9
- package/dist/contracts/oauth-resources.js +64 -1
- package/dist/contracts/oauth-scope-actions.d.ts +27 -3
- package/dist/contracts/oauth-scope-actions.js +18 -8
- package/dist/contracts/operations.d.ts +1 -1
- package/dist/contracts/partner-account.d.ts +629 -0
- package/dist/contracts/partner-account.js +18 -0
- package/dist/contracts/principal-assertion.d.ts +74 -1
- package/dist/contracts/principal-assertion.js +67 -3
- package/dist/contracts/publish-archive.d.ts +22 -1
- package/dist/contracts/push-new.d.ts +3 -3
- package/dist/contracts/push-new.js +1 -1
- package/dist/contracts/quotas.js +2 -1
- package/dist/contracts/repository-connections.d.ts +10 -6
- package/dist/contracts/repository-connections.js +15 -0
- package/dist/contracts/resources.d.ts +6 -5
- package/dist/contracts/resources.js +7 -0
- package/dist/contracts/route-inventory.d.ts +74 -19
- package/dist/contracts/route-inventory.js +20 -6
- package/dist/contracts/runtime-api.d.ts +415 -4
- package/dist/contracts/runtime-api.js +60 -15
- package/dist/contracts/runtime-app.d.ts +6 -1
- package/dist/contracts/runtime-components.d.ts +646 -18
- package/dist/contracts/runtime-components.js +304 -188
- package/dist/contracts/runtime-services.d.ts +15 -0
- package/dist/contracts/runtime-services.js +25 -0
- package/dist/contracts/runtime-storage.d.ts +32 -0
- package/dist/contracts/runtime-storage.js +37 -0
- package/dist/contracts/source-workspaces.d.ts +511 -0
- package/dist/contracts/source-workspaces.js +276 -0
- package/dist/contracts/space-config-spacefast.d.ts +394 -0
- package/dist/contracts/space-config-spacefast.js +70 -0
- package/dist/contracts/space-config.d.ts +177 -90
- package/dist/contracts/space-config.js +77 -92
- package/dist/contracts/spaces.d.ts +132 -24
- package/dist/contracts/spaces.js +77 -13
- package/dist/contracts/superadmin-connectors.d.ts +371 -0
- package/dist/contracts/superadmin-connectors.js +61 -0
- package/dist/contracts/superadmin-emails.d.ts +1 -1
- package/dist/contracts/superadmin-emails.js +1 -1
- package/dist/contracts/superadmin-entities.d.ts +105 -0
- package/dist/contracts/superadmin-entities.js +64 -0
- package/dist/contracts/superadmin-runtime.d.ts +35 -116
- package/dist/contracts/superadmin-runtime.js +13 -69
- package/dist/contracts/superadmin-search.d.ts +12 -14
- package/dist/contracts/superadmin-search.js +2 -2
- package/dist/contracts/superadmin-spaces.d.ts +15 -72
- package/dist/contracts/superadmin-spaces.js +2 -7
- package/dist/contracts/superadmin-teams.d.ts +12 -0
- package/dist/contracts/superadmin-teams.js +7 -1
- package/dist/contracts/superadmin-tenants.d.ts +44 -16
- package/dist/contracts/superadmin.d.ts +2 -2
- package/dist/contracts/tags.d.ts +12 -12
- package/dist/contracts/teams.d.ts +29 -1
- package/dist/contracts/teams.js +24 -2
- package/dist/contracts/tenants.d.ts +98 -0
- package/dist/contracts/tenants.js +20 -0
- package/dist/contracts/transfers.d.ts +92 -0
- package/dist/contracts/transfers.js +37 -0
- package/dist/contracts/usage.d.ts +9 -1
- package/dist/contracts/usage.js +2 -0
- package/dist/contracts/visual-review.d.ts +448 -0
- package/dist/contracts/visual-review.js +156 -0
- package/dist/contracts/wordpress-php-toolkit.json +9 -0
- package/dist/contracts/work-mode.d.ts +24 -0
- package/dist/contracts/work-mode.js +17 -0
- package/dist/contracts/wp-cli.d.ts +66 -0
- package/dist/contracts/wp-cli.js +68 -0
- package/dist/contracts/zero-catalog.d.ts +29 -0
- package/dist/contracts/zero-catalog.js +55 -0
- package/dist/contracts/zero-platform-abilities.generated.d.ts +31 -0
- package/dist/contracts/zero-platform-abilities.generated.js +373 -0
- package/dist/contracts/zero-spacefast.d.ts +444 -0
- package/dist/contracts/zero-spacefast.js +149 -0
- package/dist/contracts/zero-types.d.ts +47 -0
- package/dist/contracts/zero-types.js +263 -0
- package/dist/contracts/zero.d.ts +781 -14
- package/dist/contracts/zero.js +204 -10
- package/dist/dashboard-paths/index.d.ts +2 -2
- package/dist/dashboard-paths/route-reservations.generated.d.ts +2 -2
- package/dist/dashboard-paths/route-reservations.generated.js +5 -0
- package/dist/docs/agent-prose.d.ts +1 -1
- package/dist/docs/agent-prose.js +15 -18
- package/dist/docs/agent-setup.d.ts +1 -1
- package/dist/docs/agent-setup.js +5 -13
- package/dist/docs/catalog.d.ts +64 -28
- package/dist/docs/catalog.js +155 -28
- package/dist/docs/error-docs.d.ts +365 -17
- package/dist/docs/error-docs.js +369 -21
- package/dist/docs/reference-urls.js +1 -1
- package/dist/docs/skills.d.ts +84 -84
- package/dist/docs/skills.js +66 -47
- package/dist/docs/start-prompts.d.ts +14 -0
- package/dist/docs/start-prompts.js +20 -0
- package/dist/utils/account-labels.d.ts +7 -0
- package/dist/utils/account-labels.js +15 -0
- package/dist/utils/auth.d.ts +1 -0
- package/dist/utils/auth.js +1 -0
- package/dist/utils/credential-policy.d.ts +22 -1
- package/dist/utils/credential-policy.js +55 -6
- package/dist/utils/local-space-state.d.ts +7 -0
- package/dist/utils/local-space-state.js +7 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.js +144 -0
- package/dist/utils/page-routes.d.ts +9 -0
- package/dist/utils/page-routes.js +82 -0
- package/dist/utils/pages.d.ts +2 -0
- package/dist/utils/pages.js +7 -0
- package/dist/utils/publish-form-data.d.ts +2 -0
- package/dist/utils/publish-form-data.js +2 -0
- package/dist/utils/publish-policy-spacefast.d.ts +13 -0
- package/dist/utils/publish-policy-spacefast.js +117 -0
- package/dist/utils/publish-policy.d.ts +22 -16
- package/dist/utils/publish-policy.fixtures.json +15 -0
- package/dist/utils/publish-policy.js +62 -139
- package/dist/utils/query-client.js +9 -1
- package/dist/utils/runtime-upload.d.ts +4 -0
- package/dist/utils/runtime-upload.js +5 -0
- package/dist/utils/space-config.d.ts +2 -3
- package/dist/utils/space-config.js +1 -1
- package/dist/utils/uploaded-source.d.ts +4 -0
- package/dist/utils/uploaded-source.js +12 -0
- package/dist/visual-review.d.ts +4 -0
- package/dist/visual-review.js +208 -0
- package/dist/vocabulary.d.ts +38 -0
- package/dist/vocabulary.js +55 -0
- package/package.json +7 -2
- package/dist/agents/registry/deeplink-probes.d.ts +0 -23
- package/dist/agents/registry/deeplink-probes.js +0 -18
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The module `sf zero types` writes into a Zero project.
|
|
3
|
+
*
|
|
4
|
+
* Three things a project's types depend on live in the platform rather than in
|
|
5
|
+
* the project's own source, and each one is only knowable by asking: the
|
|
6
|
+
* content model the live version compiled, the Ability catalog that version
|
|
7
|
+
* publishes alongside the engine's own sets, and the database schema the broker
|
|
8
|
+
* validates against. A capsule author can read all three from the dashboard and
|
|
9
|
+
* retype them by hand; this prints them instead.
|
|
10
|
+
*
|
|
11
|
+
* The output is self-contained on purpose — no imports, because it lands in
|
|
12
|
+
* someone else's project where a dependency on `@spacefast/common` would be an
|
|
13
|
+
* imposition. That is the same rule `contentModelSdkModule` follows, and its
|
|
14
|
+
* output is embedded here verbatim rather than re-derived: it already prints
|
|
15
|
+
* exactly the content-model half of this file.
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
import { contentModelSdkModule, printContentModelSchema } from "./content-model-sdk.js";
|
|
19
|
+
import { contentAbilityTypeName } from "./content-model.js";
|
|
20
|
+
/** Zero manages these three on every row; a capsule cannot declare them. */
|
|
21
|
+
const MANAGED_ROW_COLUMNS = [
|
|
22
|
+
["id", "string"],
|
|
23
|
+
["createdAt", "string"],
|
|
24
|
+
["updatedAt", "string"],
|
|
25
|
+
];
|
|
26
|
+
const JSON_VALUE_TYPE = "ZeroJsonValue";
|
|
27
|
+
function tableTypeName(name) {
|
|
28
|
+
return `${contentAbilityTypeName(name)}Row`;
|
|
29
|
+
}
|
|
30
|
+
function columnType(column) {
|
|
31
|
+
const base = column.type === "json"
|
|
32
|
+
? JSON_VALUE_TYPE
|
|
33
|
+
: column.type === "string"
|
|
34
|
+
? "string"
|
|
35
|
+
: column.type === "number"
|
|
36
|
+
? "number"
|
|
37
|
+
: "boolean";
|
|
38
|
+
return column.nullable ? `${base} | null` : base;
|
|
39
|
+
}
|
|
40
|
+
function propertyKey(name) {
|
|
41
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The row type for one table, as a reader gets it back.
|
|
45
|
+
*
|
|
46
|
+
* The managed columns lead because they are on every row and the capsule never
|
|
47
|
+
* declared them, so a reader who did not write this table still knows what is
|
|
48
|
+
* there. The physical names the deployment assigns — the `sf_<space>_<table>_…`
|
|
49
|
+
* rewriting the control plane does — deliberately do not appear: they are
|
|
50
|
+
* plumbing, and a generated type that leaked them would break on a rename that
|
|
51
|
+
* changes nothing about the data.
|
|
52
|
+
*/
|
|
53
|
+
function printTable(table) {
|
|
54
|
+
const members = [
|
|
55
|
+
...MANAGED_ROW_COLUMNS.map(([name, type]) => ` readonly ${name}: ${type};`),
|
|
56
|
+
...table.columns.map((column) => ` readonly ${propertyKey(column.name)}: ${columnType(column)};`),
|
|
57
|
+
];
|
|
58
|
+
return [
|
|
59
|
+
`/** A row of the \`${table.name}\` table. */`,
|
|
60
|
+
`export type ${tableTypeName(table.name)} = {`,
|
|
61
|
+
...members,
|
|
62
|
+
"};",
|
|
63
|
+
"",
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
/** How the catalog spells an Ability's authorization requirement in a doc comment. */
|
|
67
|
+
function requirementSentence(ability) {
|
|
68
|
+
return ability.requires.kind === "wordpress"
|
|
69
|
+
? `Requires the WordPress capability \`${ability.requires.capability}\`.`
|
|
70
|
+
: ability.requires.capabilities.length === 0
|
|
71
|
+
? "Requires no Grant capability."
|
|
72
|
+
: `Requires the Grant ${ability.requires.capabilities.length === 1 ? "capability" : "capabilities"} ${ability.requires.capabilities.map((capability) => `\`${capability}\``).join(", ")}.`;
|
|
73
|
+
}
|
|
74
|
+
function printAbilityCatalog(abilities) {
|
|
75
|
+
if (abilities.length === 0) {
|
|
76
|
+
return [
|
|
77
|
+
"/** This Space publishes no Abilities. */",
|
|
78
|
+
"export type ZeroAbilityCatalog = Readonly<Record<string, never>>;",
|
|
79
|
+
"",
|
|
80
|
+
"export const zeroAbilityCatalog = {} as const;",
|
|
81
|
+
"",
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
// The catalog keys every entry by product id, in both the type and the value.
|
|
85
|
+
// Two rows under one id would emit a duplicate key that fails to compile, so
|
|
86
|
+
// refuse to print a broken module and name the id instead. The control plane
|
|
87
|
+
// rejects a content Ability that collides with a platform one at compile, so
|
|
88
|
+
// reaching this is a malformed catalog rather than ordinary input.
|
|
89
|
+
const seenIds = new Set();
|
|
90
|
+
for (const ability of abilities) {
|
|
91
|
+
if (seenIds.has(ability.id)) {
|
|
92
|
+
throw new Error(`The Ability catalog lists ${JSON.stringify(ability.id)} twice.`);
|
|
93
|
+
}
|
|
94
|
+
seenIds.add(ability.id);
|
|
95
|
+
}
|
|
96
|
+
const lines = [
|
|
97
|
+
"/**",
|
|
98
|
+
" * Every Ability this Space publishes, keyed by product id.",
|
|
99
|
+
" *",
|
|
100
|
+
" * Two origins are merged here and both are callable the same way. The",
|
|
101
|
+
" * `zero-wp-users` and `zero-storage` sets come from the runtime engine and are",
|
|
102
|
+
" * there whatever the capsule declares; the `zero-content` set was compiled from",
|
|
103
|
+
" * the capsule and moves with a rollback.",
|
|
104
|
+
" */",
|
|
105
|
+
"export type ZeroAbilityCatalog = {",
|
|
106
|
+
];
|
|
107
|
+
for (const ability of abilities) {
|
|
108
|
+
const requires = ability.requires.kind === "wordpress"
|
|
109
|
+
? `{ readonly kind: "wordpress"; readonly capability: ${JSON.stringify(ability.requires.capability)} }`
|
|
110
|
+
: `{ readonly kind: "grant"; readonly capabilities: readonly [${ability.requires.capabilities.map((capability) => JSON.stringify(capability)).join(", ")}] }`;
|
|
111
|
+
lines.push(` /** ${requirementSentence(ability)} */`, ` ${JSON.stringify(ability.id)}: {`, ` readonly input: ${ability.inputSchema === null ? "unknown" : printContentModelSchema(ability.inputSchema)};`, ` readonly output: ${ability.outputSchema === null ? "unknown" : printContentModelSchema(ability.outputSchema)};`, ` readonly mode: ${JSON.stringify(ability.mode)};`, ` readonly requires: ${requires};`, " };");
|
|
112
|
+
}
|
|
113
|
+
lines.push("};", "");
|
|
114
|
+
lines.push("/** The same catalog as a value, for dispatching by name. */", "export const zeroAbilityCatalog = {", ...abilities.map((ability) => ` ${JSON.stringify(ability.id)}: ${JSON.stringify({
|
|
115
|
+
name: ability.name,
|
|
116
|
+
category: ability.category,
|
|
117
|
+
mode: ability.mode,
|
|
118
|
+
requires: ability.requires,
|
|
119
|
+
})},`), "} as const;", "");
|
|
120
|
+
return lines;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The WordPress REST route each resource kind answers on.
|
|
124
|
+
*
|
|
125
|
+
* A declared collection's items are `post` rows carrying a collection taxonomy
|
|
126
|
+
* term, which is why it reads `wp/v2/posts` and is narrowed by the term rather
|
|
127
|
+
* than by a post type of its own.
|
|
128
|
+
*/
|
|
129
|
+
const CONTENT_READ_ROUTES = {
|
|
130
|
+
posts: "wp/v2/posts",
|
|
131
|
+
pages: "wp/v2/pages",
|
|
132
|
+
media: "wp/v2/media",
|
|
133
|
+
collection: "wp/v2/posts",
|
|
134
|
+
};
|
|
135
|
+
/** The collection taxonomy the content-model kernel registers on `post`. */
|
|
136
|
+
const CONTENT_COLLECTION_TAXONOMY = "zero_collection";
|
|
137
|
+
/**
|
|
138
|
+
* The term a collection's items carry, spelled exactly as
|
|
139
|
+
* `spacefast_content_model_collection_term_slug()` mints it. Two places compute
|
|
140
|
+
* this and they must agree, so the rule is restated here rather than guessed:
|
|
141
|
+
* `sf-<first 16 hex of sha256(spaceId)>-<resource id with . and _ as ->`.
|
|
142
|
+
*/
|
|
143
|
+
function collectionTermSlug(spaceId, resourceId) {
|
|
144
|
+
const hash = createHash("sha256").update(spaceId).digest("hex").slice(0, 16);
|
|
145
|
+
return `sf-${hash}-${resourceId.replaceAll(".", "-").replaceAll("_", "-")}`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The reads an island or a capsule makes against this Space's own content.
|
|
149
|
+
*
|
|
150
|
+
* Printed as plain object literals, not as calls into the SDK: this module
|
|
151
|
+
* lands in someone else's project and imports nothing. What each entry returns
|
|
152
|
+
* is structurally a `ZeroQueryOptions`, so `useQuery(content.posts.list())` is
|
|
153
|
+
* the same line whether it runs in an island on a content page or in a capsule
|
|
154
|
+
* SPA — one data layer, two backends.
|
|
155
|
+
*/
|
|
156
|
+
function printContentReads(source) {
|
|
157
|
+
const resources = source.contentModel?.wordpress.resources ?? [];
|
|
158
|
+
if (resources.length === 0)
|
|
159
|
+
return [];
|
|
160
|
+
const lines = [
|
|
161
|
+
"/**",
|
|
162
|
+
" * Reads against this Space's own content, over its WordPress REST surface.",
|
|
163
|
+
" *",
|
|
164
|
+
" * Same-origin and credential-less: a `publicRead` resource answers an",
|
|
165
|
+
" * anonymous reader, and one that is not needs a session. Pass any parameters",
|
|
166
|
+
" * WordPress accepts (`per_page`, `search`, `slug`, …).",
|
|
167
|
+
" */",
|
|
168
|
+
"export const content = {",
|
|
169
|
+
];
|
|
170
|
+
for (const resource of resources) {
|
|
171
|
+
const route = CONTENT_READ_ROUTES[resource.kind];
|
|
172
|
+
const term = resource.kind === "collection" && source.space !== null
|
|
173
|
+
? collectionTermSlug(source.space.id, resource.id)
|
|
174
|
+
: null;
|
|
175
|
+
if (resource.kind === "collection" && term === null) {
|
|
176
|
+
// Without a Space there is no term to name, and a read that fetched every
|
|
177
|
+
// post while claiming to be one collection would be worse than absent.
|
|
178
|
+
lines.push(` // \`${resource.id}\` is a collection; its term is Space-scoped, so run`, " // `sf zero types` against a Space to generate its read.");
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const params = term === null
|
|
182
|
+
? "...params"
|
|
183
|
+
: `${JSON.stringify(CONTENT_COLLECTION_TAXONOMY)}: ${JSON.stringify(term)}, ...params`;
|
|
184
|
+
lines.push(` ${propertyKey(resource.name)}: {`, ` /** ${resource.label}. ${resource.publicRead
|
|
185
|
+
? "publicRead: an anonymous reader may make this call."
|
|
186
|
+
: "Not publicRead: this call needs a session that may read it."} */`, " list: (params: Readonly<Record<string, string | number | boolean>> = {}) => ({", ` name: "content:content.${resource.id}.list",`, ` args: [{ route: ${JSON.stringify(route)}, params: { ${params} } }],`, " }),", " },");
|
|
187
|
+
}
|
|
188
|
+
lines.push("} as const;", "");
|
|
189
|
+
return lines;
|
|
190
|
+
}
|
|
191
|
+
function header(source) {
|
|
192
|
+
const origin = source.space === null
|
|
193
|
+
? "Generated by `sf zero types` from this project's local capsule compile."
|
|
194
|
+
: `Generated by \`sf zero types\` from the space ${source.space.slug} (${source.space.id}).`;
|
|
195
|
+
const lines = ["// GENERATED FILE — DO NOT EDIT.", "//", `// ${origin}`];
|
|
196
|
+
if (source.versionId !== null) {
|
|
197
|
+
lines.push(`// Live version: ${source.versionId}`);
|
|
198
|
+
}
|
|
199
|
+
if (source.contentModel !== null) {
|
|
200
|
+
lines.push(`// Content model revision: ${source.contentModel.revision}`);
|
|
201
|
+
}
|
|
202
|
+
lines.push("//", "// Regenerate: sf zero types", "// Verify in CI: sf zero types --check", "");
|
|
203
|
+
return lines;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Prints the whole `zero-types` module.
|
|
207
|
+
*
|
|
208
|
+
* Section order follows what a reader reaches for: the content model first
|
|
209
|
+
* because it is what most capsules are written against, then the Ability
|
|
210
|
+
* catalog that says what may be called and by whom, then the database rows.
|
|
211
|
+
*/
|
|
212
|
+
export function zeroTypesModule(source) {
|
|
213
|
+
const sections = [header(source).join("\n")];
|
|
214
|
+
sections.push(source.contentModel === null
|
|
215
|
+
? [
|
|
216
|
+
"// ── Content model ─────────────────────────────────────────────────────────",
|
|
217
|
+
"//",
|
|
218
|
+
"// This Space's live version declares no content model, so there are no",
|
|
219
|
+
"// content Abilities and no content types to generate.",
|
|
220
|
+
"",
|
|
221
|
+
].join("\n")
|
|
222
|
+
: [
|
|
223
|
+
"// ── Content model ─────────────────────────────────────────────────────────",
|
|
224
|
+
"",
|
|
225
|
+
contentModelSdkModule(source.contentModel),
|
|
226
|
+
"",
|
|
227
|
+
...printContentReads(source),
|
|
228
|
+
].join("\n"));
|
|
229
|
+
sections.push([
|
|
230
|
+
"// ── Ability catalog ───────────────────────────────────────────────────────",
|
|
231
|
+
"",
|
|
232
|
+
...printAbilityCatalog(source.abilities),
|
|
233
|
+
].join("\n"));
|
|
234
|
+
const dbLines = [
|
|
235
|
+
"// ── Database ──────────────────────────────────────────────────────────────",
|
|
236
|
+
"",
|
|
237
|
+
];
|
|
238
|
+
if (source.tables.some((table) => table.columns.some((column) => column.type === "json"))) {
|
|
239
|
+
dbLines.push("/** What a `json` column holds. */", `export type ${JSON_VALUE_TYPE} =`, " | string", " | number", " | boolean", " | null", ` | readonly ${JSON_VALUE_TYPE}[]`, ` | { readonly [key: string]: ${JSON_VALUE_TYPE} };`, "");
|
|
240
|
+
}
|
|
241
|
+
if (source.tables.length === 0) {
|
|
242
|
+
dbLines.push("/** This capsule declares no tables. */", "export type ZeroTables = Readonly<Record<string, never>>;", "");
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// Distinct table names can flatten onto one row-type identifier (`user_posts`
|
|
246
|
+
// and `user__posts` both give `UserPostsRow`), which would emit a duplicate
|
|
247
|
+
// `export type` that fails to compile. Refuse to print it and name the tables.
|
|
248
|
+
const seenTypeNames = new Map();
|
|
249
|
+
for (const table of source.tables) {
|
|
250
|
+
const typeName = tableTypeName(table.name);
|
|
251
|
+
const collided = seenTypeNames.get(typeName);
|
|
252
|
+
if (collided !== undefined) {
|
|
253
|
+
throw new Error(`Tables \`${collided}\` and \`${table.name}\` both generate the row type \`${typeName}\`.`);
|
|
254
|
+
}
|
|
255
|
+
seenTypeNames.set(typeName, table.name);
|
|
256
|
+
}
|
|
257
|
+
for (const table of source.tables)
|
|
258
|
+
dbLines.push(...printTable(table));
|
|
259
|
+
dbLines.push("/** Every table this capsule declares, keyed by its capsule name. */", "export type ZeroTables = {", ...source.tables.map((table) => ` readonly ${propertyKey(table.name)}: ${tableTypeName(table.name)};`), "};", "");
|
|
260
|
+
}
|
|
261
|
+
sections.push(dbLines.join("\n"));
|
|
262
|
+
return sections.join("\n");
|
|
263
|
+
}
|