@spacefast/common 0.0.5 → 0.0.6
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/connect-targets.d.ts +133 -0
- package/dist/agents/connect-targets.js +224 -0
- package/dist/brand.d.ts +1 -0
- package/dist/brand.js +5 -0
- package/dist/config/domains.d.ts +12 -6
- package/dist/config/domains.js +30 -38
- package/dist/contracts/access.d.ts +825 -125
- package/dist/contracts/access.js +771 -148
- package/dist/contracts/activity.d.ts +1 -1
- package/dist/contracts/activity.js +28 -2
- package/dist/contracts/annotations.d.ts +2 -4
- package/dist/contracts/api-keys.d.ts +3 -4
- package/dist/contracts/api-keys.js +9 -6
- package/dist/contracts/archives.d.ts +8 -2
- package/dist/contracts/archives.js +11 -4
- package/dist/contracts/billing.d.ts +0 -9
- package/dist/contracts/builds.d.ts +25 -21
- package/dist/contracts/builds.js +12 -0
- package/dist/contracts/common.d.ts +2 -0
- package/dist/contracts/common.js +4 -0
- package/dist/contracts/continuation.d.ts +0 -3
- package/dist/contracts/countries.d.ts +2 -0
- package/dist/contracts/countries.js +261 -0
- package/dist/contracts/deployments.d.ts +34 -34
- package/dist/contracts/device-auth.d.ts +4 -11
- package/dist/contracts/device-auth.js +4 -0
- package/dist/contracts/docs.d.ts +119 -0
- package/dist/contracts/docs.js +51 -0
- package/dist/contracts/domains.d.ts +96 -54
- package/dist/contracts/domains.js +26 -4
- package/dist/contracts/enums.d.ts +15 -16
- package/dist/contracts/enums.js +25 -14
- package/dist/contracts/error-code-meta.d.ts +72 -0
- package/dist/contracts/error-code-meta.js +96 -10
- package/dist/contracts/error-codes.d.ts +1 -1
- package/dist/contracts/error-codes.js +14 -0
- package/dist/contracts/events.d.ts +1 -1
- package/dist/contracts/features.d.ts +76 -6
- package/dist/contracts/features.js +178 -13
- package/dist/contracts/git.d.ts +2 -8
- package/dist/contracts/ids.d.ts +5 -0
- package/dist/contracts/ids.js +5 -0
- package/dist/contracts/mcp.d.ts +8 -10
- package/dist/contracts/me.js +1 -1
- package/dist/contracts/oauth-resources.d.ts +19 -8
- package/dist/contracts/oauth-resources.js +44 -13
- package/dist/contracts/platform.d.ts +0 -102
- package/dist/contracts/platform.js +0 -50
- package/dist/contracts/push-new.d.ts +4 -4
- package/dist/contracts/quotas.d.ts +2 -0
- package/dist/contracts/quotas.js +8 -0
- package/dist/contracts/repository-connections.d.ts +6 -8
- package/dist/contracts/resources.d.ts +97 -13
- package/dist/contracts/resources.js +26 -2
- package/dist/contracts/routes.d.ts +0 -2
- package/dist/contracts/runtime-api.d.ts +361 -39
- package/dist/contracts/runtime-api.js +275 -6
- package/dist/contracts/sites.d.ts +19 -2
- package/dist/contracts/sites.js +21 -0
- package/dist/contracts/space-config.d.ts +201 -2
- package/dist/contracts/space-config.js +135 -5
- package/dist/contracts/spaces.d.ts +364 -193
- package/dist/contracts/spaces.js +40 -8
- package/dist/contracts/superadmin-emails.d.ts +4 -2
- package/dist/contracts/superadmin-emails.js +8 -0
- package/dist/contracts/superadmin-queues.d.ts +26 -26
- package/dist/contracts/superadmin-spaces.d.ts +170 -42
- package/dist/contracts/superadmin.d.ts +6 -93
- package/dist/contracts/superadmin.js +6 -14
- package/dist/contracts/tags.d.ts +10 -9
- package/dist/contracts/tags.js +2 -1
- package/dist/contracts/teams.d.ts +21 -22
- package/dist/contracts/teams.js +0 -1
- package/dist/contracts/theme-json.d.ts +30 -0
- package/dist/contracts/theme-json.js +48 -0
- package/dist/contracts/variables.d.ts +0 -2
- package/dist/contracts/variables.js +0 -5
- package/dist/contracts/webhooks.d.ts +2 -0
- package/dist/contracts/webhooks.js +1 -1
- package/dist/contracts/zero.d.ts +5 -10
- package/dist/docs/agent-prose.d.ts +43 -3
- package/dist/docs/agent-prose.js +146 -7
- package/dist/docs/agent-setup.js +45 -13
- package/dist/docs/agent-solutions.d.ts +5 -5
- package/dist/docs/agent-solutions.js +2 -2
- package/dist/docs/catalog.d.ts +650 -0
- package/dist/docs/catalog.js +758 -0
- package/dist/docs/error-docs.d.ts +0 -2
- package/dist/docs/error-docs.js +77 -35
- package/dist/docs/index-build.d.ts +17 -0
- package/dist/docs/index-build.js +24 -0
- package/dist/docs/search.d.ts +54 -0
- package/dist/docs/search.js +96 -0
- package/dist/docs/skill-distribution.d.ts +5 -3
- package/dist/docs/skill-distribution.js +8 -8
- package/dist/utils/access-match.d.ts +39 -0
- package/dist/utils/access-match.js +296 -0
- package/dist/utils/auth-redirect.d.ts +3 -1
- package/dist/utils/auth-redirect.js +21 -1
- package/dist/utils/build-settings.d.ts +6 -0
- package/dist/utils/build-settings.js +429 -46
- package/dist/utils/claim-token.d.ts +8 -0
- package/dist/utils/claim-token.js +23 -2
- package/dist/utils/content-type.d.ts +1 -0
- package/dist/utils/content-type.js +1 -1
- package/dist/utils/credential-policy.d.ts +54 -0
- package/dist/utils/{access-policy.js → credential-policy.js} +28 -2
- package/dist/utils/gate-theme.d.ts +61 -0
- package/dist/utils/gate-theme.js +217 -0
- package/dist/utils/git-repository.d.ts +0 -1
- package/dist/utils/git-repository.js +0 -3
- package/dist/utils/id-hints.d.ts +8 -0
- package/dist/utils/id-hints.js +61 -0
- package/dist/utils/local-space-state.d.ts +91 -0
- package/dist/utils/local-space-state.js +251 -0
- package/dist/utils/oauth-signed-query.d.ts +8 -0
- package/dist/utils/oauth-signed-query.js +26 -0
- package/dist/utils/publish-detection.d.ts +0 -8
- package/dist/utils/publish-detection.js +0 -93
- package/dist/utils/publish-policy.d.ts +6 -5
- package/dist/utils/publish-policy.js +71 -7
- package/dist/utils/query-keys.d.ts +15 -4
- package/dist/utils/query-keys.js +27 -4
- package/dist/utils/runtime-paths.d.ts +0 -1
- package/dist/utils/runtime-paths.js +0 -1
- package/dist/utils/runtime-upload-batch.d.ts +18 -0
- package/dist/utils/runtime-upload-batch.js +90 -0
- package/dist/utils/runtime-upload.d.ts +2 -0
- package/dist/utils/runtime-upload.js +5 -0
- package/dist/utils/space-config.d.ts +4 -0
- package/dist/utils/space-config.js +10 -1
- package/dist/utils/space-theme.d.ts +2 -0
- package/dist/utils/space-theme.js +9 -0
- package/dist/utils/static-runtime-policy.d.ts +0 -21
- package/dist/utils/static-runtime-policy.js +19 -103
- package/dist/utils/upload-session.d.ts +1 -1
- package/dist/utils/wpcom-auth-redirects.d.ts +32 -2
- package/dist/utils/wpcom-auth-redirects.js +26 -10
- package/dist/vocabulary.d.ts +130 -30
- package/dist/vocabulary.js +77 -36
- package/package.json +16 -1
- package/dist/contracts/account.d.ts +0 -28
- package/dist/contracts/account.js +0 -54
- package/dist/contracts/intercom.d.ts +0 -6
- package/dist/contracts/intercom.js +0 -5
- package/dist/contracts/telemetry.d.ts +0 -2
- package/dist/contracts/telemetry.js +0 -1
- package/dist/utils/access-policy.d.ts +0 -39
- package/dist/utils/error-display.d.ts +0 -7
- package/dist/utils/error-display.js +0 -42
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
export const LOCAL_SPACE_STATE_DIR_NAME = ".spacefast";
|
|
5
|
+
export const LEGACY_LOCAL_SPACE_STATE_DIR_NAME = ".stattic";
|
|
6
|
+
export const LOCAL_SPACE_LINK_FILE_NAME = "space.json";
|
|
7
|
+
export const LOCAL_SPACE_STATE_FILE_NAME = "state.json";
|
|
8
|
+
/**
|
|
9
|
+
* Local Spacefast checkout contract.
|
|
10
|
+
*
|
|
11
|
+
* `.spacefast/space.json` is the committable selection axis: it names which
|
|
12
|
+
* space a checkout targets (`space`) and may carry non-secret provider/team
|
|
13
|
+
* coordinates (`team`, `apiBaseUrl`). It must not carry credentials.
|
|
14
|
+
*
|
|
15
|
+
* `.spacefast/state.json` is the local credential/cache axis: it records the
|
|
16
|
+
* resolved `spaceId`, provider `apiUrl`, anonymous `claimToken` before claim,
|
|
17
|
+
* durable `accessToken` after continuation, and small publish caches such as
|
|
18
|
+
* `lastVersionId`. It is secret, machine-written, gitignored, and merge-written
|
|
19
|
+
* so newer tools preserve unknown fields from older/newer tools.
|
|
20
|
+
*/
|
|
21
|
+
export const localSpaceLinkSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
team: z.string().min(1).optional(),
|
|
24
|
+
space: z.string().min(1),
|
|
25
|
+
apiBaseUrl: z.string().min(1).optional(),
|
|
26
|
+
})
|
|
27
|
+
.loose();
|
|
28
|
+
export const localSpaceStateSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
spaceId: z.string().min(1).optional(),
|
|
31
|
+
apiUrl: z.string().min(1).optional(),
|
|
32
|
+
teamSlug: z.string().min(1).optional(),
|
|
33
|
+
claimToken: z.string().min(1).optional(),
|
|
34
|
+
claimUrl: z.string().min(1).optional(),
|
|
35
|
+
expiresAt: z.string().min(1).optional(),
|
|
36
|
+
accessToken: z.string().min(1).optional(),
|
|
37
|
+
lastVersionId: z.string().min(1).optional(),
|
|
38
|
+
lastVersionUrl: z.string().min(1).optional(),
|
|
39
|
+
lastSpaceUrl: z.string().min(1).optional(),
|
|
40
|
+
})
|
|
41
|
+
.loose();
|
|
42
|
+
export function localSpaceStateDir(root) {
|
|
43
|
+
return path.join(root, LOCAL_SPACE_STATE_DIR_NAME);
|
|
44
|
+
}
|
|
45
|
+
export function localSpaceStatePath(root) {
|
|
46
|
+
return path.join(localSpaceStateDir(root), LOCAL_SPACE_STATE_FILE_NAME);
|
|
47
|
+
}
|
|
48
|
+
export function localSpaceLinkPath(root) {
|
|
49
|
+
return path.join(localSpaceStateDir(root), LOCAL_SPACE_LINK_FILE_NAME);
|
|
50
|
+
}
|
|
51
|
+
function legacyStatePath(root) {
|
|
52
|
+
return path.join(root, LEGACY_LOCAL_SPACE_STATE_DIR_NAME, LOCAL_SPACE_STATE_FILE_NAME);
|
|
53
|
+
}
|
|
54
|
+
function legacyLinkPath(root) {
|
|
55
|
+
return path.join(root, LEGACY_LOCAL_SPACE_STATE_DIR_NAME, LOCAL_SPACE_LINK_FILE_NAME);
|
|
56
|
+
}
|
|
57
|
+
async function readJsonFile(filePath) {
|
|
58
|
+
const raw = await readFile(filePath, "utf8").catch(() => undefined);
|
|
59
|
+
if (raw === undefined)
|
|
60
|
+
return undefined;
|
|
61
|
+
try {
|
|
62
|
+
return JSON.parse(raw);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function parseState(value) {
|
|
69
|
+
const parsed = localSpaceStateSchema.safeParse(value);
|
|
70
|
+
return parsed.success ? parsed.data : null;
|
|
71
|
+
}
|
|
72
|
+
function parseLink(value) {
|
|
73
|
+
const parsed = localSpaceLinkSchema.safeParse(value);
|
|
74
|
+
return parsed.success ? parsed.data : null;
|
|
75
|
+
}
|
|
76
|
+
function linkSpaceId(link) {
|
|
77
|
+
return link?.space.startsWith("spc_") ? link.space : undefined;
|
|
78
|
+
}
|
|
79
|
+
export async function readLocalSpaceLink(root) {
|
|
80
|
+
return (await readLocalSpaceLinkWithPath(root))?.link ?? null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Like readLocalSpaceLink, but reports WHICH file matched — callers surface the
|
|
84
|
+
* legacy `.stattic/space.json` path to users so migrations stay visible.
|
|
85
|
+
*/
|
|
86
|
+
export async function readLocalSpaceLinkWithPath(root) {
|
|
87
|
+
const primary = parseLink(await readJsonFile(localSpaceLinkPath(root)));
|
|
88
|
+
if (primary) {
|
|
89
|
+
return { link: primary, path: localSpaceLinkPath(root) };
|
|
90
|
+
}
|
|
91
|
+
const legacy = parseLink(await readJsonFile(legacyLinkPath(root)));
|
|
92
|
+
return legacy ? { link: legacy, path: legacyLinkPath(root) } : null;
|
|
93
|
+
}
|
|
94
|
+
export async function readLocalSpaceStateAt(root) {
|
|
95
|
+
const statePath = localSpaceStatePath(root);
|
|
96
|
+
const state = parseState(await readJsonFile(statePath)) ??
|
|
97
|
+
parseState(await readJsonFile(legacyStatePath(root)));
|
|
98
|
+
const linkPath = localSpaceLinkPath(root);
|
|
99
|
+
const link = parseLink(await readJsonFile(linkPath)) ?? parseLink(await readJsonFile(legacyLinkPath(root)));
|
|
100
|
+
if (!state && !link)
|
|
101
|
+
return null;
|
|
102
|
+
return {
|
|
103
|
+
root,
|
|
104
|
+
statePath: state ? statePath : null,
|
|
105
|
+
linkPath: link ? linkPath : null,
|
|
106
|
+
link,
|
|
107
|
+
state,
|
|
108
|
+
spaceId: state?.spaceId ?? linkSpaceId(link),
|
|
109
|
+
claimToken: state?.claimToken,
|
|
110
|
+
accessToken: state?.accessToken,
|
|
111
|
+
apiUrl: state?.apiUrl ?? link?.apiBaseUrl,
|
|
112
|
+
claimUrl: state?.claimUrl,
|
|
113
|
+
expiresAt: state?.expiresAt,
|
|
114
|
+
lastVersionId: state?.lastVersionId,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function isWithinBoundary(current, boundary) {
|
|
118
|
+
const relative = path.relative(boundary, current);
|
|
119
|
+
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Walk up from `startDir` to the filesystem root (or `boundary`, when given),
|
|
123
|
+
* returning the first non-null result of `probe`. Shared by every "nearest
|
|
124
|
+
* checkout marker" lookup (state+link discovery here, the CLI's link-only
|
|
125
|
+
* discovery) so the traversal rules live in one place.
|
|
126
|
+
*/
|
|
127
|
+
export async function findUpward(probe, startDir = process.cwd(), boundary) {
|
|
128
|
+
let current = path.resolve(startDir);
|
|
129
|
+
const resolvedBoundary = boundary ? path.resolve(boundary) : undefined;
|
|
130
|
+
if (resolvedBoundary && !isWithinBoundary(current, resolvedBoundary)) {
|
|
131
|
+
current = resolvedBoundary;
|
|
132
|
+
}
|
|
133
|
+
for (;;) {
|
|
134
|
+
const found = await probe(current);
|
|
135
|
+
if (found)
|
|
136
|
+
return found;
|
|
137
|
+
if (resolvedBoundary && current === resolvedBoundary)
|
|
138
|
+
return null;
|
|
139
|
+
const parent = path.dirname(current);
|
|
140
|
+
if (parent === current)
|
|
141
|
+
return null;
|
|
142
|
+
if (resolvedBoundary && !isWithinBoundary(parent, resolvedBoundary))
|
|
143
|
+
return null;
|
|
144
|
+
current = parent;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export async function discoverLocalSpaceState(startDir = process.cwd(), boundary) {
|
|
148
|
+
return findUpward(readLocalSpaceStateAt, startDir, boundary);
|
|
149
|
+
}
|
|
150
|
+
async function writeJsonAtomic(filePath, value, mode) {
|
|
151
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
152
|
+
const tempPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
153
|
+
try {
|
|
154
|
+
await writeFile(tempPath, `${JSON.stringify(value, null, 2)}\n`, {
|
|
155
|
+
encoding: "utf8",
|
|
156
|
+
...(mode ? { mode } : {}),
|
|
157
|
+
});
|
|
158
|
+
if (mode) {
|
|
159
|
+
await chmod(tempPath, mode).catch(() => undefined);
|
|
160
|
+
}
|
|
161
|
+
await rename(tempPath, filePath);
|
|
162
|
+
if (mode) {
|
|
163
|
+
await chmod(filePath, mode).catch(() => undefined);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
await rm(tempPath, { force: true }).catch(() => undefined);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function ensureStateGitignored(root) {
|
|
172
|
+
const gitignorePath = path.join(root, ".gitignore");
|
|
173
|
+
const entry = `${LOCAL_SPACE_STATE_DIR_NAME}/${LOCAL_SPACE_STATE_FILE_NAME}`;
|
|
174
|
+
const raw = await readFile(gitignorePath, "utf8").catch(() => "");
|
|
175
|
+
const lines = raw.split(/\r?\n/);
|
|
176
|
+
if (lines.includes(entry))
|
|
177
|
+
return;
|
|
178
|
+
const prefix = raw.length > 0 && !raw.endsWith("\n") ? "\n" : "";
|
|
179
|
+
await writeFile(gitignorePath, `${raw}${prefix}${entry}\n`, "utf8");
|
|
180
|
+
}
|
|
181
|
+
function assignDefined(target, input) {
|
|
182
|
+
for (const [key, value] of Object.entries(input)) {
|
|
183
|
+
if (value === undefined) {
|
|
184
|
+
delete target[key];
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
target[key] = value;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function assignPresent(target, input) {
|
|
192
|
+
for (const [key, value] of Object.entries(input)) {
|
|
193
|
+
if (value !== undefined) {
|
|
194
|
+
target[key] = value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export async function writeLocalSpaceLink(root, link) {
|
|
199
|
+
const filePath = localSpaceLinkPath(root);
|
|
200
|
+
const payload = localSpaceLinkSchema.parse({
|
|
201
|
+
space: link.space,
|
|
202
|
+
...(link.team ? { team: link.team } : {}),
|
|
203
|
+
...(link.apiBaseUrl ? { apiBaseUrl: link.apiBaseUrl } : {}),
|
|
204
|
+
});
|
|
205
|
+
await writeJsonAtomic(filePath, payload);
|
|
206
|
+
return filePath;
|
|
207
|
+
}
|
|
208
|
+
export async function writeLocalSpaceState(root, state) {
|
|
209
|
+
const filePath = localSpaceStatePath(root);
|
|
210
|
+
const payload = localSpaceStateSchema.parse(state);
|
|
211
|
+
await writeJsonAtomic(filePath, payload, 0o600);
|
|
212
|
+
await ensureStateGitignored(root);
|
|
213
|
+
return filePath;
|
|
214
|
+
}
|
|
215
|
+
export async function saveLocalSpaceState(root, input) {
|
|
216
|
+
const existing = parseState(await readJsonFile(localSpaceStatePath(root))) ??
|
|
217
|
+
parseState(await readJsonFile(legacyStatePath(root))) ??
|
|
218
|
+
{};
|
|
219
|
+
const next = { ...existing };
|
|
220
|
+
assignPresent(next, {
|
|
221
|
+
spaceId: input.spaceId,
|
|
222
|
+
apiUrl: input.apiUrl,
|
|
223
|
+
teamSlug: input.teamSlug,
|
|
224
|
+
lastVersionId: input.lastVersionId,
|
|
225
|
+
lastVersionUrl: input.lastVersionUrl,
|
|
226
|
+
lastSpaceUrl: input.lastSpaceUrl,
|
|
227
|
+
});
|
|
228
|
+
if (input.accessToken) {
|
|
229
|
+
assignDefined(next, {
|
|
230
|
+
accessToken: input.accessToken,
|
|
231
|
+
claimToken: undefined,
|
|
232
|
+
claimUrl: undefined,
|
|
233
|
+
expiresAt: undefined,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
else if (input.claimToken) {
|
|
237
|
+
assignDefined(next, {
|
|
238
|
+
claimToken: input.claimToken,
|
|
239
|
+
claimUrl: input.claimUrl,
|
|
240
|
+
expiresAt: input.expiresAt,
|
|
241
|
+
accessToken: undefined,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const statePath = await writeLocalSpaceState(root, next);
|
|
245
|
+
const existingLink = await readLocalSpaceLink(root);
|
|
246
|
+
const wroteLink = !existingLink;
|
|
247
|
+
if (!existingLink) {
|
|
248
|
+
await writeLocalSpaceLink(root, { space: input.spaceId, apiBaseUrl: input.apiUrl });
|
|
249
|
+
}
|
|
250
|
+
return { statePath, linkPath: localSpaceLinkPath(root), wroteLink };
|
|
251
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The signed OAuth authorize continuation carried by a query string, or null
|
|
3
|
+
* when there isn't one. Better Auth's signature covers every param it sent
|
|
4
|
+
* (the set is self-declared in `ba_param`) — anything extra that later joined
|
|
5
|
+
* the URL (a returnTo, a tracking param) must be dropped before the query is
|
|
6
|
+
* sent back, or verification fails.
|
|
7
|
+
*/
|
|
8
|
+
export declare function signedOAuthQuerySubset(query: string): string | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Better Auth's OAuth authorize endpoint hands interaction prompts (login,
|
|
2
|
+
// consent) to the dashboard by redirecting with the ENTIRE authorize query,
|
|
3
|
+
// HMAC-signed by the auth server (`sig` + `exp` + `ba_*` bookkeeping params).
|
|
4
|
+
// Verification hashes the query verbatim, so it must round-trip byte-exact.
|
|
5
|
+
/**
|
|
6
|
+
* The signed OAuth authorize continuation carried by a query string, or null
|
|
7
|
+
* when there isn't one. Better Auth's signature covers every param it sent
|
|
8
|
+
* (the set is self-declared in `ba_param`) — anything extra that later joined
|
|
9
|
+
* the URL (a returnTo, a tracking param) must be dropped before the query is
|
|
10
|
+
* sent back, or verification fails.
|
|
11
|
+
*/
|
|
12
|
+
export function signedOAuthQuerySubset(query) {
|
|
13
|
+
const params = new URLSearchParams(query);
|
|
14
|
+
if (!params.get("client_id") || !params.get("sig"))
|
|
15
|
+
return null;
|
|
16
|
+
const signedNames = new Set(params.getAll("ba_param"));
|
|
17
|
+
if (signedNames.size === 0)
|
|
18
|
+
return null;
|
|
19
|
+
const signed = new URLSearchParams();
|
|
20
|
+
for (const [key, value] of params) {
|
|
21
|
+
if (key === "sig" || key === "ba_param" || signedNames.has(key)) {
|
|
22
|
+
signed.append(key, value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return signed.toString();
|
|
26
|
+
}
|
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
import type { SpaceConfig } from "../contracts/space-config.js";
|
|
2
|
-
import type { SpaceSettingsPatch } from "./space-config.js";
|
|
3
1
|
export declare function detectSpaFromPaths(paths: Iterable<string>): boolean;
|
|
4
2
|
export declare function detectSpaFallbackFromPaths(paths: Iterable<string>): string | null;
|
|
5
|
-
export type SpaceSettingsFromConfigJson = SpaceSettingsPatch & {
|
|
6
|
-
title?: string;
|
|
7
|
-
password?: string | null;
|
|
8
|
-
};
|
|
9
|
-
export declare function parseSpaceSettingsFromConfigJson(raw: string | undefined): SpaceSettingsFromConfigJson | null;
|
|
10
|
-
export declare function spaceConfigFromSettings(base: SpaceConfig | null | undefined, patch: SpaceSettingsPatch): SpaceConfig;
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
function isRecord(value) {
|
|
2
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
-
}
|
|
4
1
|
export function detectSpaFromPaths(paths) {
|
|
5
2
|
return detectSpaFallbackFromPaths(paths) !== null;
|
|
6
3
|
}
|
|
@@ -26,93 +23,3 @@ export function detectSpaFallbackFromPaths(paths) {
|
|
|
26
23
|
entry === "asset-manifest.json");
|
|
27
24
|
return hasSpaAssets ? "/index.html" : null;
|
|
28
25
|
}
|
|
29
|
-
// Parses the legacy-vocabulary keys of a local `.stattic/config.json` file
|
|
30
|
-
// (title/mode/spa/password/viewer). Platform SpaceConfig keys are handled
|
|
31
|
-
// separately by the publish flow.
|
|
32
|
-
export function parseSpaceSettingsFromConfigJson(raw) {
|
|
33
|
-
if (!raw) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
let parsedJson;
|
|
37
|
-
try {
|
|
38
|
-
parsedJson = JSON.parse(raw);
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
if (!isRecord(parsedJson)) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const settings = {};
|
|
47
|
-
if (parsedJson.title && typeof parsedJson.title === "string") {
|
|
48
|
-
settings.title = parsedJson.title;
|
|
49
|
-
}
|
|
50
|
-
if (parsedJson.mode === "website" || parsedJson.mode === "files") {
|
|
51
|
-
settings.mode = parsedJson.mode;
|
|
52
|
-
}
|
|
53
|
-
if (typeof parsedJson.spa === "boolean") {
|
|
54
|
-
settings.spa = parsedJson.spa;
|
|
55
|
-
}
|
|
56
|
-
if (parsedJson.password === null || typeof parsedJson.password === "string") {
|
|
57
|
-
settings.password = parsedJson.password;
|
|
58
|
-
}
|
|
59
|
-
if (isRecord(parsedJson.viewer)) {
|
|
60
|
-
const viewer = {};
|
|
61
|
-
for (const key of ["title", "description", "ogImagePath"]) {
|
|
62
|
-
const value = parsedJson.viewer[key];
|
|
63
|
-
if (value === null || typeof value === "string") {
|
|
64
|
-
viewer[key] = value;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
if (Object.keys(viewer).length > 0) {
|
|
68
|
-
settings.viewer = viewer;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return Object.keys(settings).length > 0 ? settings : null;
|
|
72
|
-
}
|
|
73
|
-
// Compiles the legacy `.stattic/config.json` serving vocabulary (mode/spa/viewer)
|
|
74
|
-
// onto a SpaceConfig overlay. Files mode = directory listing with no index; SPA =
|
|
75
|
-
// the legacy "/index.html" fallback; viewer fields map onto meta. Only the publish flow
|
|
76
|
-
// reads a legacy config.json, so this translation lives beside its parser.
|
|
77
|
-
export function spaceConfigFromSettings(base, patch) {
|
|
78
|
-
const config = { ...base };
|
|
79
|
-
if (patch.mode === "files") {
|
|
80
|
-
config.listing = true;
|
|
81
|
-
config.index = false;
|
|
82
|
-
}
|
|
83
|
-
else if (patch.mode === "website") {
|
|
84
|
-
delete config.listing;
|
|
85
|
-
delete config.index;
|
|
86
|
-
}
|
|
87
|
-
if (patch.spa === true) {
|
|
88
|
-
config.fallback = "/index.html";
|
|
89
|
-
}
|
|
90
|
-
else if (patch.spa === false) {
|
|
91
|
-
delete config.fallback;
|
|
92
|
-
}
|
|
93
|
-
if (patch.viewer) {
|
|
94
|
-
const meta = { ...config.meta };
|
|
95
|
-
const entries = [
|
|
96
|
-
["title", patch.viewer.title],
|
|
97
|
-
["description", patch.viewer.description],
|
|
98
|
-
["image", patch.viewer.ogImagePath],
|
|
99
|
-
];
|
|
100
|
-
for (const [key, value] of entries) {
|
|
101
|
-
if (value === undefined)
|
|
102
|
-
continue;
|
|
103
|
-
if (value === null || value === "") {
|
|
104
|
-
delete meta[key];
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
meta[key] = value;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (Object.keys(meta).length > 0) {
|
|
111
|
-
config.meta = meta;
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
delete config.meta;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return config;
|
|
118
|
-
}
|
|
@@ -21,6 +21,7 @@ export declare function firstStaticUploadPathViolation(paths: string[], options?
|
|
|
21
21
|
export type PublishManifestCaps = {
|
|
22
22
|
maxFiles?: number | null | undefined;
|
|
23
23
|
maxFileBytes?: number | null | undefined;
|
|
24
|
+
maxTotalBytes?: number | null | undefined;
|
|
24
25
|
};
|
|
25
26
|
export type PublishManifestError = {
|
|
26
27
|
code: ErrorCode;
|
|
@@ -50,16 +51,16 @@ export declare function validatePublishManifest<T extends {
|
|
|
50
51
|
path: string;
|
|
51
52
|
size: number;
|
|
52
53
|
}>(files: readonly T[], caps?: PublishManifestCaps): PublishManifestResult<T>;
|
|
53
|
-
export declare
|
|
54
|
+
export declare const ANONYMOUS_SERVE_CONTENT_TYPES: readonly ["text/*", "image/*", "font/*", "application/json", "application/manifest+json", "application/javascript", "application/gzip", "application/xml", "application/rss+xml", "application/atom+xml"];
|
|
55
|
+
export type FreePlanContentPolicyOptions = {
|
|
54
56
|
claimedSpace?: boolean;
|
|
55
|
-
}
|
|
57
|
+
};
|
|
58
|
+
export declare function freePlanCanUploadPath(filePath: string, options?: FreePlanContentPolicyOptions): boolean;
|
|
56
59
|
export declare function freePlanCanUploadContentType(contentType: string | undefined): boolean;
|
|
57
60
|
export declare function filterFreePlanManifest<T extends {
|
|
58
61
|
path: string;
|
|
59
62
|
contentType?: string | undefined;
|
|
60
|
-
}>(files: readonly T[], options?: {
|
|
61
|
-
claimedSpace?: boolean;
|
|
62
|
-
}): {
|
|
63
|
+
}>(files: readonly T[], options?: FreePlanContentPolicyOptions): {
|
|
63
64
|
allowed: T[];
|
|
64
65
|
ignored: string[];
|
|
65
66
|
};
|
|
@@ -27,6 +27,9 @@ const IGNORED_EXACT_PATHS = new Set([
|
|
|
27
27
|
".env.test",
|
|
28
28
|
".npmrc",
|
|
29
29
|
".netrc",
|
|
30
|
+
// CLI checkout state (current dir name plus the legacy pre-rename one —
|
|
31
|
+
// user archives may contain either; both stay out of every publish).
|
|
32
|
+
".spacefast/state.json",
|
|
30
33
|
".stattic/state.json",
|
|
31
34
|
"_routes.json",
|
|
32
35
|
]);
|
|
@@ -52,14 +55,36 @@ const SENSITIVE_FILE_PATTERNS = [
|
|
|
52
55
|
];
|
|
53
56
|
// Denied runtime private/control paths (spec "Static path policy").
|
|
54
57
|
const STATIC_EXECUTION_CONTROL_FILES = new Set([".htaccess", ".user.ini"]);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
// Reserved runtime namespace segments are matched by PREFIX: the runtime owns
|
|
59
|
+
// `/__spacefast/*` plus `__spacefast_generated/`, and the `__stattic` spelling
|
|
60
|
+
// (`/__stattic_probe` today, more `/__stattic/*` routes planned) stays
|
|
61
|
+
// reserved the same way. Mid-segment occurrences are ordinary content.
|
|
62
|
+
const STATIC_RUNTIME_CONTROL_SEGMENT_PREFIXES = ["__spacefast", "__stattic"];
|
|
63
|
+
// Both the current and the legacy control-path spellings stay denied: spaces
|
|
64
|
+
// published before the `.stattic` → `.spacefast` rename still serve from the
|
|
65
|
+
// legacy on-disk layout, and user archives may carry either name.
|
|
66
|
+
const STATIC_RUNTIME_CONTROL_PATHS = new Set([
|
|
67
|
+
".well-known/spacefast-runtime",
|
|
68
|
+
".well-known/stattic-runtime",
|
|
69
|
+
]);
|
|
70
|
+
const STATIC_RUNTIME_CONTROL_PREFIXES = [
|
|
71
|
+
".spacefast/storage",
|
|
72
|
+
".spacefast/engine",
|
|
73
|
+
".stattic/storage",
|
|
74
|
+
".stattic/engine",
|
|
75
|
+
];
|
|
58
76
|
export function normalizePublishPath(relativePath) {
|
|
59
77
|
return relativePath.replace(/\\/g, "/").replace(/^\/+/g, "");
|
|
60
78
|
}
|
|
61
79
|
export function publishPathIgnored(relativePath) {
|
|
62
80
|
const path = normalizePublishPath(relativePath);
|
|
81
|
+
// The agent state dirs hold one secret (state.json) plus committable tooling
|
|
82
|
+
// (space.json). Drop only those files at any depth so a checkout archived one
|
|
83
|
+
// level too high never ships a claim token — but keep serving legitimate
|
|
84
|
+
// content in the same dirs (e.g. the legacy .stattic/routes.json convention).
|
|
85
|
+
if (/(?:^|\/)\.(?:spacefast|stattic)\/(?:state|space)\.json$/.test(path)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
63
88
|
if (IGNORED_EXACT_PATHS.has(path) || /(?:^|\/)\.next\/cache(?:\/|$)/.test(path)) {
|
|
64
89
|
return true;
|
|
65
90
|
}
|
|
@@ -154,7 +179,10 @@ export function staticUploadPathViolation(path, options = {}) {
|
|
|
154
179
|
if (reservedRuntimeControlFiles?.has(lowerName) && lowerPath === lowerName) {
|
|
155
180
|
return pathViolation("static_runtime_control_path_not_supported", "Static deploys cannot upload runtime control paths.", normalizedPath);
|
|
156
181
|
}
|
|
157
|
-
const controlSegment = segments.find((segment) =>
|
|
182
|
+
const controlSegment = segments.find((segment) => {
|
|
183
|
+
const lowerSegment = segment.toLowerCase();
|
|
184
|
+
return STATIC_RUNTIME_CONTROL_SEGMENT_PREFIXES.some((prefix) => lowerSegment.startsWith(prefix));
|
|
185
|
+
});
|
|
158
186
|
if (controlSegment) {
|
|
159
187
|
return pathViolation("static_runtime_control_path_not_supported", "Static deploys cannot upload runtime control paths.", normalizedPath);
|
|
160
188
|
}
|
|
@@ -240,6 +268,13 @@ export function validatePublishManifest(files, caps = {}) {
|
|
|
240
268
|
warnings: [],
|
|
241
269
|
};
|
|
242
270
|
}
|
|
271
|
+
// Checkout state and credential paths (.spacefast/, .git/, .env*, …) are
|
|
272
|
+
// silently dropped rather than rejected: agents that archive one level too
|
|
273
|
+
// high must never publish a claim token to the live site, and failing the
|
|
274
|
+
// whole manifest for it would punish the common accident.
|
|
275
|
+
if (publishPathIgnored(canonicalPath)) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
243
278
|
// Case-only-differing paths are distinct (paths are byte-exact and
|
|
244
279
|
// case-sensitive) but cannot round-trip case-insensitive filesystems.
|
|
245
280
|
const lowercase = canonicalPath.toLowerCase();
|
|
@@ -271,13 +306,14 @@ export function validatePublishManifest(files, caps = {}) {
|
|
|
271
306
|
warnings: [],
|
|
272
307
|
};
|
|
273
308
|
}
|
|
309
|
+
const maxTotalBytes = Math.min(MAX_VERSION_TOTAL_BYTES, caps.maxTotalBytes && caps.maxTotalBytes > 0 ? caps.maxTotalBytes : MAX_VERSION_TOTAL_BYTES);
|
|
274
310
|
const totalBytes = canonicalFiles.reduce((sum, file) => sum + file.size, 0);
|
|
275
|
-
if (totalBytes >
|
|
311
|
+
if (totalBytes > maxTotalBytes) {
|
|
276
312
|
return {
|
|
277
313
|
error: {
|
|
278
314
|
code: "version_total_bytes_exceeded",
|
|
279
|
-
message: `Version exceeds the ${
|
|
280
|
-
details: { totalBytes, limit:
|
|
315
|
+
message: `Version exceeds the ${maxTotalBytes} byte total size limit for this plan.`,
|
|
316
|
+
details: { totalBytes, limit: maxTotalBytes },
|
|
281
317
|
},
|
|
282
318
|
files: null,
|
|
283
319
|
warnings: [],
|
|
@@ -319,6 +355,25 @@ const FREE_PLAN_ALLOWED_UPLOAD_EXTENSIONS = new Set([
|
|
|
319
355
|
".ttf",
|
|
320
356
|
".otf",
|
|
321
357
|
]);
|
|
358
|
+
// THE anonymous content enforcement (accept-and-scan posture): uploads are
|
|
359
|
+
// accepted like any free publish, but until the space is claimed the runtime
|
|
360
|
+
// only serves these content types, pushed as the generic route-config
|
|
361
|
+
// `content_types` allowlist (exact types or `prefix/*` wildcards; the engine
|
|
362
|
+
// enforces the list without knowing it means "anonymous"). Web-page content
|
|
363
|
+
// only — no opaque octet-streams, archives (except scanned gzip, which
|
|
364
|
+
// pagefind search indexes depend on), documents, or media containers.
|
|
365
|
+
export const ANONYMOUS_SERVE_CONTENT_TYPES = [
|
|
366
|
+
"text/*",
|
|
367
|
+
"image/*",
|
|
368
|
+
"font/*",
|
|
369
|
+
"application/json",
|
|
370
|
+
"application/manifest+json",
|
|
371
|
+
"application/javascript",
|
|
372
|
+
"application/gzip",
|
|
373
|
+
"application/xml",
|
|
374
|
+
"application/rss+xml",
|
|
375
|
+
"application/atom+xml",
|
|
376
|
+
];
|
|
322
377
|
const LINE_SPLIT_PATTERN = /\r?\n/;
|
|
323
378
|
const BASIC_AUTH_HEADER_PATTERN = /^basic-auth\s*:/i;
|
|
324
379
|
function extensionForPath(filePath) {
|
|
@@ -333,6 +388,13 @@ function freePlanDeniedExecutablePath(filePath) {
|
|
|
333
388
|
.split("/")
|
|
334
389
|
.some((segment) => segment === "bin");
|
|
335
390
|
}
|
|
391
|
+
// Acceptance is deliberately identical for claimed-free and unclaimed
|
|
392
|
+
// anonymous spaces (accept-and-scan posture): rejecting file types at upload
|
|
393
|
+
// adds no safety — the bytes reach us before any scan either way — so
|
|
394
|
+
// publishes are accepted, every file goes through the scan pipeline, and the
|
|
395
|
+
// SERVE-time content-type allowlist (ANONYMOUS_SERVE_CONTENT_TYPES via the
|
|
396
|
+
// route-config `content_types` policy) is what keeps opaque binaries dark
|
|
397
|
+
// until the space is claimed.
|
|
336
398
|
export function freePlanCanUploadPath(filePath, options) {
|
|
337
399
|
const path = normalizePublishPath(filePath);
|
|
338
400
|
// Root Spacefast config files are platform machinery, not user content (spec "Space
|
|
@@ -363,6 +425,8 @@ export function freePlanCanUploadContentType(contentType) {
|
|
|
363
425
|
normalized === "application/javascript" ||
|
|
364
426
|
normalized === "application/json" ||
|
|
365
427
|
normalized === "application/manifest+json" ||
|
|
428
|
+
// Gzip stays allowed for anonymous spaces too: pagefind search indexes
|
|
429
|
+
// ship as gzip fragments, and ClamAV decompresses gzip when scanning.
|
|
366
430
|
normalized === "application/gzip" ||
|
|
367
431
|
normalized === "image/svg+xml" ||
|
|
368
432
|
normalized === "application/xml" ||
|
|
@@ -4,8 +4,9 @@ export declare const qk: {
|
|
|
4
4
|
accountSessions: () => readonly ["account", "sessions"];
|
|
5
5
|
accountConnections: () => readonly ["account", "connections"];
|
|
6
6
|
accountInvitations: () => readonly ["account", "invitations"];
|
|
7
|
-
apiTokens: () => readonly ["api-tokens"];
|
|
7
|
+
apiTokens: (teamId?: string) => readonly ["api-tokens"] | readonly ["api-tokens", string];
|
|
8
8
|
agentAccounts: () => readonly ["agent-accounts"];
|
|
9
|
+
myShelf: () => readonly ["my-shelf"];
|
|
9
10
|
mcpDashboard: () => readonly ["mcp", "dashboard"];
|
|
10
11
|
mcpApproval: (id: string) => readonly ["mcp", "approval", string];
|
|
11
12
|
teams: () => readonly ["teams", "list"];
|
|
@@ -28,13 +29,18 @@ export declare const qk: {
|
|
|
28
29
|
spaceByRef: (teamRef: string, spaceRef: string) => readonly ["spaces", "by-ref", string, string];
|
|
29
30
|
spaceVersions: (id: string) => readonly ["spaces", string, "versions"];
|
|
30
31
|
spaceCollaboration: (id: string) => readonly ["spaces", string, "collaboration"];
|
|
32
|
+
spaceCollaborationEmbedConfig: (id: string) => readonly ["spaces", string, "collaboration", "embed-config"];
|
|
31
33
|
spaceAnnotations: (id: string) => readonly ["spaces", string, "annotations"];
|
|
32
34
|
spaceActivity: (id: string, limit: number) => readonly ["spaces", string, "activity", number];
|
|
33
35
|
spaceDeployments: (id: string) => readonly ["spaces", string, "deployments"];
|
|
34
36
|
spaceTags: (id: string) => readonly ["spaces", string, "tags"];
|
|
35
|
-
spaceTagVersion: (id: string, versionId: string) => readonly ["spaces", string, "tags",
|
|
37
|
+
spaceTagVersion: (id: string, versionId: string) => readonly ["spaces", string, "tags", string];
|
|
38
|
+
spaceTagDiff: (id: string, versionId: string) => readonly ["spaces", string, "tags", string, "diff"];
|
|
39
|
+
spaceTagReleases: (id: string) => readonly ["spaces", string, "tags", "releases"];
|
|
40
|
+
spaceTagsEffective: (id: string) => readonly ["spaces", string, "tags", "effective"];
|
|
36
41
|
build: (id: string) => readonly ["builds", string];
|
|
37
|
-
buildLogs: (id: string) => readonly ["builds", string, "logs"];
|
|
42
|
+
buildLogs: (id: string, limit?: number) => readonly ["builds", string, "logs"] | readonly ["builds", string, "logs", number];
|
|
43
|
+
spaceBuilds: (id: string) => readonly ["spaces", string, "builds"];
|
|
38
44
|
spaceRepositoryConnection: (id: string, connectionType?: string) => readonly ["spaces", string, "repository-connection", string];
|
|
39
45
|
repositoryInstallations: (spaceId: string) => readonly ["repository-connections", "installations", string];
|
|
40
46
|
repositoryInstallationRepositories: (installationId: string) => readonly ["repository-connections", "installations", string, "repositories"];
|
|
@@ -44,7 +50,7 @@ export declare const qk: {
|
|
|
44
50
|
webhook: (webhookId: string) => readonly ["webhooks", string];
|
|
45
51
|
webhookDeliveries: (webhookId: string) => readonly ["webhooks", string, "deliveries"];
|
|
46
52
|
spaceVersion: (id: string, versionId: string) => readonly ["spaces", string, "versions", string];
|
|
47
|
-
spaceVersionAnnotations: (id: string, versionId: string, status?: string) => readonly ["spaces", string, "versions", string, "annotations", string];
|
|
53
|
+
spaceVersionAnnotations: (id: string, versionId: string, status?: string) => readonly ["spaces", string, "versions", string, "annotations"] | readonly ["spaces", string, "versions", string, "annotations", string];
|
|
48
54
|
spaceVersionFiles: (id: string, versionId: string) => readonly ["spaces", string, "versions", string, "files"];
|
|
49
55
|
spaceVersionFile: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string];
|
|
50
56
|
spaceVersionFileDirectUrl: (id: string, versionId: string, path: string) => readonly ["spaces", string, "versions", string, "files", string, "direct-url"];
|
|
@@ -65,6 +71,11 @@ export declare const qk: {
|
|
|
65
71
|
spaceCertificates: (id: string) => readonly ["spaces", string, "runtime", "certificates"];
|
|
66
72
|
spaceLogs: (id: string, kind: "build" | "access" | "runtime") => readonly ["spaces", string, "logs", "build" | "runtime" | "access"];
|
|
67
73
|
spaceAnalytics: (id: string, window: string) => readonly ["spaces", string, "analytics", string];
|
|
74
|
+
spaceFirewall: (id: string) => readonly ["spaces", string, "access", "firewall"];
|
|
75
|
+
spaceAccessViews: (id: string, since?: string) => readonly ["spaces", string, "access", "views", string];
|
|
76
|
+
teamServiceTokens: (teamId: string) => readonly ["teams", string, "access", "service-tokens"];
|
|
77
|
+
teamAccessDefaults: (teamId: string) => readonly ["teams", string, "access", "defaults"];
|
|
78
|
+
teamAccessConnections: (teamId: string) => readonly ["teams", string, "access", "connections"];
|
|
68
79
|
domain: (teamId: string, ref: string) => readonly ["teams", string, "domains", string];
|
|
69
80
|
domainDiagnostics: (teamId: string, domainId: string) => readonly ["teams", string, "domains", string, "diagnostics"];
|
|
70
81
|
domainDnsCapabilities: (domainId: string) => readonly ["domains", string, "dns", "capabilities"];
|