@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 @@
|
|
|
1
|
+
export declare const AGENT_MARKETPLACE_DEFAULT_PROMPTS: readonly ["Publish this project with Spacefast and return its live and immutable URLs.", "Show the latest deployments for my Spacefast Space.", "Show the DNS and SSL status for my Spacefast Space."];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AGENT_DISTRIBUTION_PROFILE } from "./registry/core.js";
|
|
2
|
+
export const AGENT_MARKETPLACE_DEFAULT_PROMPTS = [
|
|
3
|
+
`Publish this project with ${AGENT_DISTRIBUTION_PROFILE.displayName} and return its live and immutable URLs.`,
|
|
4
|
+
`Show the latest deployments for my ${AGENT_DISTRIBUTION_PROFILE.displayName} Space.`,
|
|
5
|
+
`Show the DNS and SSL status for my ${AGENT_DISTRIBUTION_PROFILE.displayName} Space.`,
|
|
6
|
+
];
|
|
@@ -66,13 +66,10 @@ export type RegistryContext = Readonly<{
|
|
|
66
66
|
wwwOrigin: string;
|
|
67
67
|
}>;
|
|
68
68
|
/**
|
|
69
|
-
* `declared`
|
|
70
|
-
*
|
|
71
|
-
* (scripts/marketplaces/probe-deeplinks.mjs) may write `probed` or `failed`, and
|
|
72
|
-
* a `failed` deeplink is demoted out of `interactive-primary` automatically.
|
|
73
|
-
* There is deliberately no "verified" value: nothing in this file can earn it.
|
|
69
|
+
* `declared` means a human read the vendor source on `checkedAt`.
|
|
70
|
+
* Registry entries do not claim that the integration has been tested.
|
|
74
71
|
*/
|
|
75
|
-
export type RegistryVerificationStatus = "declared"
|
|
72
|
+
export type RegistryVerificationStatus = "declared";
|
|
76
73
|
export type RegistryVerification = Readonly<{
|
|
77
74
|
checkedAt: string;
|
|
78
75
|
evidence?: string;
|
|
@@ -194,7 +191,7 @@ export type AgentEntry = Readonly<{
|
|
|
194
191
|
tier: "featured" | "listed";
|
|
195
192
|
verification: RegistryVerification;
|
|
196
193
|
vendor: string;
|
|
197
|
-
wizardGroup: "claude" | "openai" | "coding-agents" | "personal-agents" | "
|
|
194
|
+
wizardGroup: "claude" | "openai" | "coding-agents" | "personal-agents" | "prompt-first" | null;
|
|
198
195
|
}>;
|
|
199
196
|
export type PresentedMethod = Readonly<{
|
|
200
197
|
/**
|
|
@@ -274,11 +271,6 @@ export declare function hostedMcpServersConfig(context: RegistryContext): string
|
|
|
274
271
|
export declare const AGENT_REGISTRY: readonly AgentEntry[];
|
|
275
272
|
export declare function getAgentEntry(id: AgentId): AgentEntry;
|
|
276
273
|
export declare function resolveAgentId(value: string): AgentId | null;
|
|
277
|
-
/**
|
|
278
|
-
* The ranking rule, as a pure function so the demote path is testable without a
|
|
279
|
-
* registry entry: a deeplink whose last probe failed is dropped from the
|
|
280
|
-
* interactive lane, and everything else sorts by its per-context rank.
|
|
281
|
-
*/
|
|
282
274
|
export declare function methodsForContext(methods: readonly IntegrationMethod[], context: PresentationContext): readonly IntegrationMethod[];
|
|
283
275
|
export declare function agentMethodsForContext(agentId: AgentId, context: PresentationContext): readonly IntegrationMethod[];
|
|
284
276
|
/**
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* reads. Runtime-specific path and config mechanics live in ./node.ts.
|
|
6
6
|
*/
|
|
7
7
|
import { serviceOrigin } from "../../config/domains.js";
|
|
8
|
-
import { DEEPLINK_PROBE_RESULTS } from "./deeplink-probes.js";
|
|
9
8
|
export const AGENT_IDS = [
|
|
10
9
|
"claude-code",
|
|
11
10
|
"claude-app",
|
|
@@ -523,10 +522,7 @@ function jsonHostedConfig(root) {
|
|
|
523
522
|
}, null, 2);
|
|
524
523
|
}
|
|
525
524
|
/**
|
|
526
|
-
*
|
|
527
|
-
* every deeplink's declared fallback resolves to a sibling method (and takes that
|
|
528
|
-
* sibling's real kind), and any probe result recorded for a deeplink overrides
|
|
529
|
-
* its `declared` verification status.
|
|
525
|
+
* Resolve every deeplink's fallback to a sibling method and its actual kind.
|
|
530
526
|
*/
|
|
531
527
|
function resolveMethods(agentId, methods) {
|
|
532
528
|
return methods.map((method) => {
|
|
@@ -536,18 +532,9 @@ function resolveMethods(agentId, methods) {
|
|
|
536
532
|
if (!target || target === method) {
|
|
537
533
|
throw new TypeError(`Agent ${agentId} deeplink "${method.id}" declares fallback "${method.fallback.id}", which is not one of its methods.`);
|
|
538
534
|
}
|
|
539
|
-
const probe = DEEPLINK_PROBE_RESULTS[`${agentId}:${method.id}`];
|
|
540
|
-
const probed = { ...method.verification };
|
|
541
|
-
if (probe) {
|
|
542
|
-
probed.checkedAt = probe.checkedAt;
|
|
543
|
-
probed.status = probe.status;
|
|
544
|
-
if (probe.evidence !== undefined)
|
|
545
|
-
probed.evidence = probe.evidence;
|
|
546
|
-
}
|
|
547
535
|
return {
|
|
548
536
|
...method,
|
|
549
537
|
fallback: { id: target.id, kind: target.kind },
|
|
550
|
-
verification: probed,
|
|
551
538
|
};
|
|
552
539
|
});
|
|
553
540
|
}
|
|
@@ -887,7 +874,7 @@ export const AGENT_REGISTRY = [
|
|
|
887
874
|
detectionHints: [],
|
|
888
875
|
kind: "chat-app",
|
|
889
876
|
tier: "listed",
|
|
890
|
-
wizardGroup: "
|
|
877
|
+
wizardGroup: "coding-agents",
|
|
891
878
|
capabilities: ["skills", "mcp-oauth"],
|
|
892
879
|
skills: { agentsDirs: true, claudeDirs: false },
|
|
893
880
|
agentsMd: "native",
|
|
@@ -1046,7 +1033,7 @@ export const AGENT_REGISTRY = [
|
|
|
1046
1033
|
detectionHints: [".factory"],
|
|
1047
1034
|
kind: "coding-agent",
|
|
1048
1035
|
tier: "listed",
|
|
1049
|
-
wizardGroup:
|
|
1036
|
+
wizardGroup: null,
|
|
1050
1037
|
capabilities: ["skills", "mcp-local", "mcp-oauth", "plugin"],
|
|
1051
1038
|
skills: { agentsDirs: true, claudeDirs: true },
|
|
1052
1039
|
agentsMd: "native",
|
|
@@ -1079,7 +1066,7 @@ export const AGENT_REGISTRY = [
|
|
|
1079
1066
|
detectionHints: [".cline"],
|
|
1080
1067
|
kind: "editor",
|
|
1081
1068
|
tier: "listed",
|
|
1082
|
-
wizardGroup:
|
|
1069
|
+
wizardGroup: null,
|
|
1083
1070
|
capabilities: ["skills", "mcp-oauth", "plugin"],
|
|
1084
1071
|
skills: { agentsDirs: true, claudeDirs: true },
|
|
1085
1072
|
agentsMd: "native",
|
|
@@ -1102,7 +1089,7 @@ export const AGENT_REGISTRY = [
|
|
|
1102
1089
|
detectionHints: [".continue"],
|
|
1103
1090
|
kind: "editor",
|
|
1104
1091
|
tier: "listed",
|
|
1105
|
-
wizardGroup:
|
|
1092
|
+
wizardGroup: null,
|
|
1106
1093
|
capabilities: ["skills"],
|
|
1107
1094
|
skills: { agentsDirs: false, claudeDirs: true },
|
|
1108
1095
|
agentsMd: "none",
|
|
@@ -1127,7 +1114,7 @@ export const AGENT_REGISTRY = [
|
|
|
1127
1114
|
detectionHints: [],
|
|
1128
1115
|
kind: "mcp-app",
|
|
1129
1116
|
tier: "listed",
|
|
1130
|
-
wizardGroup: "
|
|
1117
|
+
wizardGroup: "personal-agents",
|
|
1131
1118
|
capabilities: ["mcp-oauth", "deeplink-only"],
|
|
1132
1119
|
skills: { agentsDirs: false, claudeDirs: false },
|
|
1133
1120
|
agentsMd: "none",
|
|
@@ -1206,7 +1193,7 @@ export const AGENT_REGISTRY = [
|
|
|
1206
1193
|
detectionHints: [],
|
|
1207
1194
|
kind: "mcp-app",
|
|
1208
1195
|
tier: "listed",
|
|
1209
|
-
wizardGroup: "
|
|
1196
|
+
wizardGroup: "personal-agents",
|
|
1210
1197
|
capabilities: ["mcp-oauth", "deeplink-only"],
|
|
1211
1198
|
skills: { agentsDirs: false, claudeDirs: false },
|
|
1212
1199
|
agentsMd: "none",
|
|
@@ -1283,17 +1270,9 @@ export function getAgentEntry(id) {
|
|
|
1283
1270
|
export function resolveAgentId(value) {
|
|
1284
1271
|
return idByAlias.get(normalizeLookup(value)) ?? null;
|
|
1285
1272
|
}
|
|
1286
|
-
/**
|
|
1287
|
-
* The ranking rule, as a pure function so the demote path is testable without a
|
|
1288
|
-
* registry entry: a deeplink whose last probe failed is dropped from the
|
|
1289
|
-
* interactive lane, and everything else sorts by its per-context rank.
|
|
1290
|
-
*/
|
|
1291
1273
|
export function methodsForContext(methods, context) {
|
|
1292
1274
|
return methods
|
|
1293
1275
|
.filter((method) => method.rank[context] !== undefined)
|
|
1294
|
-
.filter((method) => method.kind !== "deeplink" ||
|
|
1295
|
-
method.verification.status !== "failed" ||
|
|
1296
|
-
context !== "interactive-primary")
|
|
1297
1276
|
.toSorted((left, right) => (left.rank[context] ?? 0) - (right.rank[context] ?? 0));
|
|
1298
1277
|
}
|
|
1299
1278
|
export function agentMethodsForContext(agentId, context) {
|
package/dist/config/domains.d.ts
CHANGED
|
@@ -17,17 +17,19 @@ export declare const PROD_ENV_DOMAIN: "spacefast.com";
|
|
|
17
17
|
/** The local-dev apex (portless serves every subdomain over HTTPS). */
|
|
18
18
|
export declare const DEV_ENV_DOMAIN: "sf.localhost";
|
|
19
19
|
/** The deployed staging apex. Not local: staging is a hosted environment. */
|
|
20
|
-
export declare const STAGING_ENV_DOMAIN: "
|
|
21
|
-
/** The deployed dev apex. Local dev is separate and stays on sf.localhost. */
|
|
22
|
-
export declare const DEV_DEPLOY_ENV_DOMAIN: "stattic.xyz";
|
|
20
|
+
export declare const STAGING_ENV_DOMAIN: "staging.spacefast.com";
|
|
23
21
|
/**
|
|
24
|
-
* The
|
|
25
|
-
* carries everywhere else: the
|
|
22
|
+
* The two environments the deploy lanes ship to, keyed by the name each one
|
|
23
|
+
* carries everywhere else: the tag map in scripts/deploy-environment.mjs,
|
|
26
24
|
* the GitHub Environment, and `SPACEFAST_ENV` on the running service. Distinct
|
|
27
|
-
* from `DeployEnv` above, which names the local stacks beside prod.
|
|
25
|
+
* from `DeployEnv` above, which names the local stacks beside prod. `dev` is
|
|
26
|
+
* only a local stack name now; the hosted dev environment is retired.
|
|
28
27
|
*/
|
|
29
|
-
export type HostedEnv = "
|
|
30
|
-
export declare const HOSTED_ENV_DOMAINS:
|
|
28
|
+
export type HostedEnv = "staging" | "prod";
|
|
29
|
+
export declare const HOSTED_ENV_DOMAINS: {
|
|
30
|
+
readonly staging: "staging.spacefast.com";
|
|
31
|
+
readonly prod: "spacefast.com";
|
|
32
|
+
};
|
|
31
33
|
/**
|
|
32
34
|
* The hosted environment a `SPACEFAST_ENV` value names, or null. `production`
|
|
33
35
|
* is accepted for `prod`: it is what the running services already carry, and
|
package/dist/config/domains.js
CHANGED
|
@@ -8,11 +8,8 @@ export const PROD_ENV_DOMAIN = "spacefast.com";
|
|
|
8
8
|
/** The local-dev apex (portless serves every subdomain over HTTPS). */
|
|
9
9
|
export const DEV_ENV_DOMAIN = "sf.localhost";
|
|
10
10
|
/** The deployed staging apex. Not local: staging is a hosted environment. */
|
|
11
|
-
export const STAGING_ENV_DOMAIN = "
|
|
12
|
-
/** The deployed dev apex. Local dev is separate and stays on sf.localhost. */
|
|
13
|
-
export const DEV_DEPLOY_ENV_DOMAIN = "stattic.xyz";
|
|
11
|
+
export const STAGING_ENV_DOMAIN = "staging.spacefast.com";
|
|
14
12
|
export const HOSTED_ENV_DOMAINS = {
|
|
15
|
-
dev: DEV_DEPLOY_ENV_DOMAIN,
|
|
16
13
|
staging: STAGING_ENV_DOMAIN,
|
|
17
14
|
prod: PROD_ENV_DOMAIN,
|
|
18
15
|
};
|
|
@@ -56,7 +53,7 @@ export function envDomainsFor(domain) {
|
|
|
56
53
|
superadmin: `superadmin.${domain}`,
|
|
57
54
|
cast: `cast.${domain}`,
|
|
58
55
|
mcp: `mcp.${domain}`,
|
|
59
|
-
push: prod ?
|
|
56
|
+
push: prod ? `git.${domain}` : `push.${domain}`,
|
|
60
57
|
fieldguide: prod ? "pitch.view.fast" : `fieldguide.${domain}`,
|
|
61
58
|
},
|
|
62
59
|
};
|
|
@@ -117,8 +114,8 @@ export function resolveViewFastApex(environment) {
|
|
|
117
114
|
if (explicit)
|
|
118
115
|
return explicit;
|
|
119
116
|
// SPACEFAST_ENV names a hosted environment only on a deployed service, where
|
|
120
|
-
// NODE_ENV is production. `dev` is
|
|
121
|
-
//
|
|
117
|
+
// NODE_ENV is production. `dev` is the local stack's name, and a local stack
|
|
118
|
+
// must keep the local apex rather than allocate under a hosted namespace.
|
|
122
119
|
const nodeEnvironment = environment.NODE_ENV?.trim().toLowerCase();
|
|
123
120
|
if (!["prod", "production"].includes(nodeEnvironment ?? ""))
|
|
124
121
|
return DEV_VIEW_FAST_APEX;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { GrantCapability } from "./grants-core.js";
|
|
3
|
+
/** Media type of the handoff document that carries a session to the runtime. */
|
|
4
|
+
export declare const ACCESS_HANDOFF_MEDIA_TYPE = "application/vnd.spacefast.access-handoff+json";
|
|
5
|
+
/**
|
|
6
|
+
* The sharing vocabulary. Capabilities are the ground truth; a role is a named
|
|
7
|
+
* set of them, ordered from least to most. This is the product's only role enum
|
|
8
|
+
* and role⇄capability mapping: every surface derives its capabilities here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ACCESS_ROLES: readonly ["viewer", "commenter", "editor", "manager"];
|
|
11
|
+
export declare const accessRoleSchema: z.ZodEnum<{
|
|
12
|
+
editor: "editor";
|
|
13
|
+
viewer: "viewer";
|
|
14
|
+
commenter: "commenter";
|
|
15
|
+
manager: "manager";
|
|
16
|
+
}>;
|
|
17
|
+
export type AccessRole = z.infer<typeof accessRoleSchema>;
|
|
18
|
+
export declare const ACCESS_ROLE_CAPABILITIES: {
|
|
19
|
+
readonly viewer: readonly ["page.view"];
|
|
20
|
+
readonly commenter: readonly ["page.view", "comments.read", "comments.write"];
|
|
21
|
+
readonly editor: readonly ["page.view", "comments.read", "comments.write", "content.publish"];
|
|
22
|
+
readonly manager: readonly ["page.view", "comments.read", "comments.write", "content.publish", "access.manage"];
|
|
23
|
+
};
|
|
24
|
+
export declare function accessRoleCapabilities(role: AccessRole): GrantCapability[];
|
|
25
|
+
/**
|
|
26
|
+
* The role a capability set amounts to: the strongest role it reaches, never
|
|
27
|
+
* more. A Grant assembled capability-by-capability need not match one exactly.
|
|
28
|
+
*/
|
|
29
|
+
export declare function accessRoleForCapabilities(capabilities: readonly GrantCapability[]): AccessRole;
|
|
30
|
+
/**
|
|
31
|
+
* Roles a forwardable secret (a Link, a password) can carry. It never publishes
|
|
32
|
+
* and never manages access; `grantSchema` enforces that on capabilities too.
|
|
33
|
+
*/
|
|
34
|
+
export declare const VISITOR_ACCESS_ROLES: readonly ["viewer", "commenter"];
|
|
35
|
+
export type VisitorAccessRole = (typeof VISITOR_ACCESS_ROLES)[number];
|
|
36
|
+
export declare function accessRoleRank(role: AccessRole): number;
|
|
37
|
+
export declare function maxAccessRole(left: AccessRole | null, right: AccessRole | null): AccessRole | null;
|
|
38
|
+
/**
|
|
39
|
+
* Canonicalizes the URL route identity used by People, Links, requests,
|
|
40
|
+
* comments, and runtime authorization.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizeAccessScopePath(input: string): string;
|
|
43
|
+
export declare const accessScopePathSchema: z.ZodString;
|
|
44
|
+
export type AccessScopePath = z.infer<typeof accessScopePathSchema>;
|
|
45
|
+
export declare function accessScopeContains(scope: string, path: string): boolean;
|
|
46
|
+
export declare const authorityReferenceSchema: z.ZodString;
|
|
47
|
+
export type AuthorityReference = z.infer<typeof authorityReferenceSchema>;
|
|
48
|
+
export declare const accountPrincipalSchema: z.ZodString;
|
|
49
|
+
export type AccountPrincipal = z.infer<typeof accountPrincipalSchema>;
|
|
50
|
+
export declare const identifiedPrincipalSchema: z.ZodString;
|
|
51
|
+
export type IdentifiedPrincipal = z.infer<typeof identifiedPrincipalSchema>;
|
|
52
|
+
export declare const accessPrincipalSchema: z.ZodUnion<readonly [z.ZodLiteral<"anonymous">, z.ZodString]>;
|
|
53
|
+
export type AccessPrincipal = z.infer<typeof accessPrincipalSchema>;
|
|
54
|
+
export declare function accountPrincipal(userId: string): AccountPrincipal;
|
|
55
|
+
/** The user id behind an account principal; null for anonymous or malformed. */
|
|
56
|
+
export declare function accountPrincipalUserId(principal: string | undefined | null): string | null;
|
|
57
|
+
/**
|
|
58
|
+
* The identity an authority reference names on its own, if any. The ONE place a
|
|
59
|
+
* class maps to an identity: at the exchange that authenticated it, never after.
|
|
60
|
+
*/
|
|
61
|
+
export declare function principalForAuthority(reference: AuthorityReference): IdentifiedPrincipal | undefined;
|
|
62
|
+
export declare const ACCESS_TOKEN_KID = "spacefast-runtime-v1";
|
|
63
|
+
export declare const ACCESS_TOKEN_ALG = "EdDSA";
|
|
64
|
+
/**
|
|
65
|
+
* The claim-schema version every platform token carries in `v`. A verifier that
|
|
66
|
+
* understands v1 refuses a token minted under a later shape.
|
|
67
|
+
*/
|
|
68
|
+
export declare const PLATFORM_TOKEN_CLAIM_VERSION: 1;
|
|
69
|
+
export declare const BLOB_GATE_DOWNLOAD_TTL_SECONDS: number;
|
|
70
|
+
/**
|
|
71
|
+
* How long an embedded version preview keeps working before the dashboard has
|
|
72
|
+
* to mint again. Same budget as a file link: the credential rides a URL, and a
|
|
73
|
+
* URL-borne credential is only safe while it rots quickly. The runtime sizes
|
|
74
|
+
* the cookie it echoes this token into from the same expiry, so the preview and
|
|
75
|
+
* its subresources die together instead of the page outliving its assets.
|
|
76
|
+
*/
|
|
77
|
+
export declare const VERSION_PREVIEW_SESSION_TTL_SECONDS: number;
|
|
78
|
+
export declare const BLOB_GATE_SCAN_TTL_SECONDS: number;
|
|
79
|
+
export declare const BLOB_GATE_UPLOAD_TTL_SECONDS: number;
|
|
80
|
+
export declare const RUNTIME_JWKS_WELL_KNOWN_FILENAME = "spacefast-runtime-jwks.json";
|
|
81
|
+
export declare const accessTokenPublicProfileSchema: z.ZodObject<{
|
|
82
|
+
name: z.ZodOptional<z.ZodString>;
|
|
83
|
+
username: z.ZodOptional<z.ZodString>;
|
|
84
|
+
avatar_url: z.ZodOptional<z.ZodURL>;
|
|
85
|
+
}, z.core.$strict>;
|
|
86
|
+
export type AccessTokenPublicProfile = z.infer<typeof accessTokenPublicProfileSchema>;
|
|
87
|
+
export declare const accessTokenPayloadSchema: z.ZodObject<{
|
|
88
|
+
v: z.ZodLiteral<1>;
|
|
89
|
+
sub: z.ZodString;
|
|
90
|
+
principal: z.ZodOptional<z.ZodString>;
|
|
91
|
+
authorities: z.ZodArray<z.ZodString>;
|
|
92
|
+
exp: z.ZodNumber;
|
|
93
|
+
nbf: z.ZodNumber;
|
|
94
|
+
iat: z.ZodNumber;
|
|
95
|
+
iss: z.ZodString;
|
|
96
|
+
aud: z.ZodString;
|
|
97
|
+
host: z.ZodString;
|
|
98
|
+
spaceId: z.ZodString;
|
|
99
|
+
sid: z.ZodString;
|
|
100
|
+
generation: z.ZodNumber;
|
|
101
|
+
emailVerified: z.ZodDefault<z.ZodBoolean>;
|
|
102
|
+
profile: z.ZodOptional<z.ZodObject<{
|
|
103
|
+
name: z.ZodOptional<z.ZodString>;
|
|
104
|
+
username: z.ZodOptional<z.ZodString>;
|
|
105
|
+
avatar_url: z.ZodOptional<z.ZodURL>;
|
|
106
|
+
}, z.core.$strict>>;
|
|
107
|
+
jti: z.ZodString;
|
|
108
|
+
purpose: z.ZodLiteral<"handoff">;
|
|
109
|
+
browserState: z.ZodOptional<z.ZodString>;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
export type AccessTokenPayload = z.infer<typeof accessTokenPayloadSchema>;
|
|
112
|
+
export declare const runtimeBearerTokenPayloadSchema: z.ZodObject<{
|
|
113
|
+
v: z.ZodLiteral<1>;
|
|
114
|
+
sub: z.ZodString;
|
|
115
|
+
principal: z.ZodOptional<z.ZodString>;
|
|
116
|
+
authorities: z.ZodArray<z.ZodString>;
|
|
117
|
+
exp: z.ZodNumber;
|
|
118
|
+
nbf: z.ZodNumber;
|
|
119
|
+
iat: z.ZodNumber;
|
|
120
|
+
iss: z.ZodString;
|
|
121
|
+
aud: z.ZodString;
|
|
122
|
+
host: z.ZodString;
|
|
123
|
+
spaceId: z.ZodString;
|
|
124
|
+
sid: z.ZodString;
|
|
125
|
+
generation: z.ZodNumber;
|
|
126
|
+
emailVerified: z.ZodDefault<z.ZodBoolean>;
|
|
127
|
+
profile: z.ZodOptional<z.ZodObject<{
|
|
128
|
+
name: z.ZodOptional<z.ZodString>;
|
|
129
|
+
username: z.ZodOptional<z.ZodString>;
|
|
130
|
+
avatar_url: z.ZodOptional<z.ZodURL>;
|
|
131
|
+
}, z.core.$strict>>;
|
|
132
|
+
jti: z.ZodString;
|
|
133
|
+
purpose: z.ZodLiteral<"runtime-bearer">;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
export type RuntimeBearerTokenPayload = z.infer<typeof runtimeBearerTokenPayloadSchema>;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// The access VOCABULARY a serving runtime needs to answer a request: what a role
|
|
3
|
+
// means in capabilities, how a URL scope is canonicalized, who a session is, and
|
|
4
|
+
// the shape of the handoff token that says so.
|
|
5
|
+
//
|
|
6
|
+
// Spacefast's directory of people, Links, access requests and team defaults —
|
|
7
|
+
// the records BEHIND those sessions — is the host's own and lives in `./access.js`.
|
|
8
|
+
/** Media type of the handoff document that carries a session to the runtime. */
|
|
9
|
+
export const ACCESS_HANDOFF_MEDIA_TYPE = "application/vnd.spacefast.access-handoff+json";
|
|
10
|
+
/**
|
|
11
|
+
* The sharing vocabulary. Capabilities are the ground truth; a role is a named
|
|
12
|
+
* set of them, ordered from least to most. This is the product's only role enum
|
|
13
|
+
* and role⇄capability mapping: every surface derives its capabilities here.
|
|
14
|
+
*/
|
|
15
|
+
export const ACCESS_ROLES = ["viewer", "commenter", "editor", "manager"];
|
|
16
|
+
export const accessRoleSchema = z.enum(ACCESS_ROLES);
|
|
17
|
+
export const ACCESS_ROLE_CAPABILITIES = {
|
|
18
|
+
viewer: ["page.view"],
|
|
19
|
+
commenter: ["page.view", "comments.read", "comments.write"],
|
|
20
|
+
editor: ["page.view", "comments.read", "comments.write", "content.publish"],
|
|
21
|
+
manager: ["page.view", "comments.read", "comments.write", "content.publish", "access.manage"],
|
|
22
|
+
};
|
|
23
|
+
export function accessRoleCapabilities(role) {
|
|
24
|
+
return [...ACCESS_ROLE_CAPABILITIES[role]];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The role a capability set amounts to: the strongest role it reaches, never
|
|
28
|
+
* more. A Grant assembled capability-by-capability need not match one exactly.
|
|
29
|
+
*/
|
|
30
|
+
export function accessRoleForCapabilities(capabilities) {
|
|
31
|
+
if (capabilities.includes("access.manage"))
|
|
32
|
+
return "manager";
|
|
33
|
+
if (capabilities.includes("content.publish"))
|
|
34
|
+
return "editor";
|
|
35
|
+
if (capabilities.includes("comments.write"))
|
|
36
|
+
return "commenter";
|
|
37
|
+
return "viewer";
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Roles a forwardable secret (a Link, a password) can carry. It never publishes
|
|
41
|
+
* and never manages access; `grantSchema` enforces that on capabilities too.
|
|
42
|
+
*/
|
|
43
|
+
export const VISITOR_ACCESS_ROLES = [
|
|
44
|
+
"viewer",
|
|
45
|
+
"commenter",
|
|
46
|
+
];
|
|
47
|
+
export function accessRoleRank(role) {
|
|
48
|
+
return ACCESS_ROLES.indexOf(role);
|
|
49
|
+
}
|
|
50
|
+
export function maxAccessRole(left, right) {
|
|
51
|
+
if (left === null)
|
|
52
|
+
return right;
|
|
53
|
+
if (right === null)
|
|
54
|
+
return left;
|
|
55
|
+
return accessRoleRank(left) >= accessRoleRank(right) ? left : right;
|
|
56
|
+
}
|
|
57
|
+
function hasUnsafeScopeCharacter(value) {
|
|
58
|
+
for (const character of value) {
|
|
59
|
+
const codePoint = character.codePointAt(0);
|
|
60
|
+
if (codePoint === undefined ||
|
|
61
|
+
codePoint <= 0x1f ||
|
|
62
|
+
codePoint === 0x7f ||
|
|
63
|
+
character === "\\" ||
|
|
64
|
+
character === "?" ||
|
|
65
|
+
character === "#") {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Canonicalizes the URL route identity used by People, Links, requests,
|
|
73
|
+
* comments, and runtime authorization.
|
|
74
|
+
*/
|
|
75
|
+
export function normalizeAccessScopePath(input) {
|
|
76
|
+
const value = input;
|
|
77
|
+
if (!value.startsWith("/") || value.startsWith("//") || hasUnsafeScopeCharacter(value)) {
|
|
78
|
+
throw new TypeError("scope must be a plain absolute URL path");
|
|
79
|
+
}
|
|
80
|
+
let decoded;
|
|
81
|
+
try {
|
|
82
|
+
decoded = decodeURIComponent(value);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
throw new TypeError("scope contains malformed percent encoding");
|
|
86
|
+
}
|
|
87
|
+
if (/%2f|%5c/iu.test(value) || hasUnsafeScopeCharacter(decoded)) {
|
|
88
|
+
throw new TypeError("scope contains an ambiguous encoded separator");
|
|
89
|
+
}
|
|
90
|
+
const segments = [];
|
|
91
|
+
for (const rawSegment of decoded.split("/")) {
|
|
92
|
+
const segment = rawSegment.normalize("NFC");
|
|
93
|
+
if (segment === "" || segment === ".")
|
|
94
|
+
continue;
|
|
95
|
+
if (segment === "..") {
|
|
96
|
+
if (segments.length === 0) {
|
|
97
|
+
throw new TypeError("scope escapes the URL root");
|
|
98
|
+
}
|
|
99
|
+
segments.pop();
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
segments.push(segment);
|
|
103
|
+
}
|
|
104
|
+
if (segments.at(-1) === "index.html") {
|
|
105
|
+
segments.pop();
|
|
106
|
+
}
|
|
107
|
+
return segments.length === 0 ? "/" : `/${segments.join("/")}`;
|
|
108
|
+
}
|
|
109
|
+
export const accessScopePathSchema = z
|
|
110
|
+
.string()
|
|
111
|
+
.min(1)
|
|
112
|
+
.max(1024)
|
|
113
|
+
.check((context) => {
|
|
114
|
+
try {
|
|
115
|
+
context.value = normalizeAccessScopePath(context.value);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
context.issues.push({
|
|
119
|
+
code: "custom",
|
|
120
|
+
input: context.value,
|
|
121
|
+
message: error instanceof Error ? error.message : "invalid access scope",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
export function accessScopeContains(scope, path) {
|
|
126
|
+
const canonicalScope = normalizeAccessScopePath(scope);
|
|
127
|
+
const canonicalPath = normalizeAccessScopePath(path);
|
|
128
|
+
return (canonicalScope === "/" ||
|
|
129
|
+
canonicalPath === canonicalScope ||
|
|
130
|
+
canonicalPath.startsWith(`${canonicalScope}/`));
|
|
131
|
+
}
|
|
132
|
+
export const authorityReferenceSchema = z
|
|
133
|
+
.string()
|
|
134
|
+
.regex(/^(member|person|link|password|machine|claim-preview|external):[A-Za-z0-9_.-]+$/);
|
|
135
|
+
// WHO a session is, orthogonal to WHAT it may do. A session has exactly one
|
|
136
|
+
// principal and any number of authorities; neither implies the other.
|
|
137
|
+
export const accountPrincipalSchema = z.string().regex(/^account:[A-Za-z0-9_-]+$/);
|
|
138
|
+
// `person:` is someone this Space invited by email and who accepted, a named
|
|
139
|
+
// identity with no platform account behind it. `external:` is a subject an
|
|
140
|
+
// identity connection vouched for. Every other authority class (Link, password,
|
|
141
|
+
// machine, claim preview) authenticates no one and leaves the session anonymous.
|
|
142
|
+
export const identifiedPrincipalSchema = z
|
|
143
|
+
.string()
|
|
144
|
+
.regex(/^(?:account|person|external):[A-Za-z0-9_.-]+$/);
|
|
145
|
+
export const accessPrincipalSchema = z.union([z.literal("anonymous"), identifiedPrincipalSchema]);
|
|
146
|
+
export function accountPrincipal(userId) {
|
|
147
|
+
return accountPrincipalSchema.parse(`account:${userId}`);
|
|
148
|
+
}
|
|
149
|
+
/** The user id behind an account principal; null for anonymous or malformed. */
|
|
150
|
+
export function accountPrincipalUserId(principal) {
|
|
151
|
+
if (!principal || !accountPrincipalSchema.safeParse(principal).success)
|
|
152
|
+
return null;
|
|
153
|
+
return principal.slice("account:".length);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The identity an authority reference names on its own, if any. The ONE place a
|
|
157
|
+
* class maps to an identity: at the exchange that authenticated it, never after.
|
|
158
|
+
*/
|
|
159
|
+
export function principalForAuthority(reference) {
|
|
160
|
+
return reference.startsWith("person:") || reference.startsWith("external:")
|
|
161
|
+
? identifiedPrincipalSchema.parse(reference)
|
|
162
|
+
: undefined;
|
|
163
|
+
}
|
|
164
|
+
// The platform token format: what a runtime verifies a handoff against.
|
|
165
|
+
export const ACCESS_TOKEN_KID = "spacefast-runtime-v1";
|
|
166
|
+
export const ACCESS_TOKEN_ALG = "EdDSA";
|
|
167
|
+
/**
|
|
168
|
+
* The claim-schema version every platform token carries in `v`. A verifier that
|
|
169
|
+
* understands v1 refuses a token minted under a later shape.
|
|
170
|
+
*/
|
|
171
|
+
export const PLATFORM_TOKEN_CLAIM_VERSION = 1;
|
|
172
|
+
export const BLOB_GATE_DOWNLOAD_TTL_SECONDS = 10 * 60;
|
|
173
|
+
/**
|
|
174
|
+
* How long an embedded version preview keeps working before the dashboard has
|
|
175
|
+
* to mint again. Same budget as a file link: the credential rides a URL, and a
|
|
176
|
+
* URL-borne credential is only safe while it rots quickly. The runtime sizes
|
|
177
|
+
* the cookie it echoes this token into from the same expiry, so the preview and
|
|
178
|
+
* its subresources die together instead of the page outliving its assets.
|
|
179
|
+
*/
|
|
180
|
+
export const VERSION_PREVIEW_SESSION_TTL_SECONDS = 10 * 60;
|
|
181
|
+
export const BLOB_GATE_SCAN_TTL_SECONDS = 60 * 60;
|
|
182
|
+
export const BLOB_GATE_UPLOAD_TTL_SECONDS = 60 * 60;
|
|
183
|
+
export const RUNTIME_JWKS_WELL_KNOWN_FILENAME = "spacefast-runtime-jwks.json";
|
|
184
|
+
// Public identity, attached only when a consumer must render the person behind
|
|
185
|
+
// an authority. The minting side normalizes a provider avatar or derives one
|
|
186
|
+
// from the email, then drops the email. Raw email and provider-private profile
|
|
187
|
+
// metadata never belong here.
|
|
188
|
+
export const accessTokenPublicProfileSchema = z
|
|
189
|
+
.object({
|
|
190
|
+
name: z.string().min(1).max(120).optional(),
|
|
191
|
+
username: z.string().min(1).max(160).optional(),
|
|
192
|
+
avatar_url: z
|
|
193
|
+
.url({ protocol: /^https?$/ })
|
|
194
|
+
.max(2_048)
|
|
195
|
+
.optional(),
|
|
196
|
+
})
|
|
197
|
+
.strict();
|
|
198
|
+
const authorityTokenPayloadClaimsSchema = z.object({
|
|
199
|
+
v: z.literal(PLATFORM_TOKEN_CLAIM_VERSION),
|
|
200
|
+
sub: authorityReferenceSchema,
|
|
201
|
+
// Who this handoff authenticated, when it authenticated anybody. Its absence
|
|
202
|
+
// means the runtime session is anonymous. Identity comes from here alone,
|
|
203
|
+
// never inferred from the authority classes below.
|
|
204
|
+
principal: identifiedPrincipalSchema.optional(),
|
|
205
|
+
authorities: z.array(authorityReferenceSchema).min(1).max(16),
|
|
206
|
+
exp: z.number().int().nonnegative(),
|
|
207
|
+
nbf: z.number().int().nonnegative(),
|
|
208
|
+
iat: z.number().int().nonnegative(),
|
|
209
|
+
iss: z.string().min(1),
|
|
210
|
+
// The Space this handoff belongs to. A Space keeps its id across claim,
|
|
211
|
+
// rename, and custom domains, so the audience is stable where a host is not.
|
|
212
|
+
aud: z.string().min(1),
|
|
213
|
+
// The lowercased serving host the handoff was minted for. The runtime rejects
|
|
214
|
+
// a token presented on any other host.
|
|
215
|
+
host: z.string().min(1),
|
|
216
|
+
spaceId: z.string().min(1),
|
|
217
|
+
// Shared opaque identity for the runtime request/session and its
|
|
218
|
+
// access-origin collaboration session. It never authorizes by itself.
|
|
219
|
+
sid: z.string().regex(/^[a-f0-9]{64}$/),
|
|
220
|
+
generation: z.number().int().nonnegative(),
|
|
221
|
+
emailVerified: z.boolean().default(false),
|
|
222
|
+
profile: accessTokenPublicProfileSchema.optional(),
|
|
223
|
+
jti: z.string().min(1),
|
|
224
|
+
});
|
|
225
|
+
export const accessTokenPayloadSchema = authorityTokenPayloadClaimsSchema.extend({
|
|
226
|
+
// Typed purpose from the one platform signer. The runtime REQUIRES exactly
|
|
227
|
+
// this value before consuming the jti, so no other purpose signed by the same
|
|
228
|
+
// key can redeem into a visitor session.
|
|
229
|
+
purpose: z.literal("handoff"),
|
|
230
|
+
// Present only when the runtime initiated an interactive browser login. The
|
|
231
|
+
// runtime compares it with its host-only HttpOnly cookie before consuming
|
|
232
|
+
// the handoff, so a copied callback cannot install a session elsewhere.
|
|
233
|
+
browserState: z
|
|
234
|
+
.string()
|
|
235
|
+
.regex(/^[a-f0-9]{64}$/)
|
|
236
|
+
.optional(),
|
|
237
|
+
});
|
|
238
|
+
export const runtimeBearerTokenPayloadSchema = authorityTokenPayloadClaimsSchema.extend({
|
|
239
|
+
// A runtime bearer is reusable until expiry. It is deliberately a different
|
|
240
|
+
// purpose from a handoff, which the runtime consumes exactly once.
|
|
241
|
+
purpose: z.literal("runtime-bearer"),
|
|
242
|
+
});
|
|
@@ -9,7 +9,7 @@ import { z } from "zod";
|
|
|
9
9
|
* person approving a device never sees two checkboxes that mean the same grant,
|
|
10
10
|
* and this set equals the hosted-MCP resource's scopes so the two converge.
|
|
11
11
|
*/
|
|
12
|
-
export declare const APPROVABLE_SCOPES: readonly ["teams:read", "teams:create", "spaces:read", "spaces:write", "spaces:rename", "publish:write", "domains:read", "domains:write"];
|
|
12
|
+
export declare const APPROVABLE_SCOPES: readonly ["teams:read", "teams:create", "teams:members.write", "spaces:read", "spaces:write", "spaces:rename", "spaces:delete", "versions:download", "publish:write", "domains:read", "domains:write", "connectors:read", "connectors:write", "connectors:execute"];
|
|
13
13
|
export type ApprovableScope = (typeof APPROVABLE_SCOPES)[number];
|
|
14
14
|
/**
|
|
15
15
|
* Whether a scope, when approved, is bounded by the holder's team role. This is
|
|
@@ -50,10 +50,10 @@ export type AccessProfile = Readonly<{
|
|
|
50
50
|
/**
|
|
51
51
|
* Named grant profiles. A profile is REQUEST INTENT — one word on device start
|
|
52
52
|
* with a server-owned meaning — never authority. Scopes are the grant
|
|
53
|
-
* vocabulary; actions are authority.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
53
|
+
* vocabulary; actions are authority. Agent access grants routine capabilities by
|
|
54
|
+
* default and leaves destructive Space deletion for explicit or temporary
|
|
55
|
+
* approval. Every capability remains capped per team by the approver's live role
|
|
56
|
+
* at request time.
|
|
57
57
|
*/
|
|
58
58
|
export declare const ACCESS_PROFILES: {
|
|
59
59
|
readonly read: {
|
|
@@ -65,9 +65,9 @@ export declare const ACCESS_PROFILES: {
|
|
|
65
65
|
readonly agent: {
|
|
66
66
|
readonly id: "agent";
|
|
67
67
|
readonly label: "Agent access";
|
|
68
|
-
readonly blurb: "Create and publish sites
|
|
69
|
-
readonly limits: "It can't
|
|
70
|
-
readonly scopes: readonly
|
|
68
|
+
readonly blurb: "Create and publish sites. Manage domains and DNS. Invite team members, create teams, and use Spacefast tools.";
|
|
69
|
+
readonly limits: "It asks for temporary approval before it deletes sites. It can't remove team members, change their roles, change billing, or mint credentials.";
|
|
70
|
+
readonly scopes: readonly ("teams:read" | "teams:create" | "teams:members.write" | "spaces:read" | "spaces:write" | "spaces:rename" | "versions:download" | "publish:write" | "domains:read" | "domains:write" | "connectors:read" | "connectors:write" | "connectors:execute")[];
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
export declare const DEFAULT_ACCESS_PROFILE_ID: AccessProfileId;
|