@noodleseed/one 0.155.0 → 0.157.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/assistant-embed-django-tests.d.ts +3 -0
- package/dist/assistant-embed-django-tests.d.ts.map +1 -0
- package/dist/assistant-embed-django-tests.js +140 -0
- package/dist/assistant-embed-django-tests.js.map +1 -0
- package/dist/assistant-embed-django.d.ts +4 -0
- package/dist/assistant-embed-django.d.ts.map +1 -0
- package/dist/assistant-embed-django.js +259 -0
- package/dist/assistant-embed-django.js.map +1 -0
- package/dist/assistant-embed-installation.d.ts +29 -0
- package/dist/assistant-embed-installation.d.ts.map +1 -0
- package/dist/assistant-embed-installation.js +124 -0
- package/dist/assistant-embed-installation.js.map +1 -0
- package/dist/assistant-embed-profile.d.ts +8 -0
- package/dist/assistant-embed-profile.d.ts.map +1 -0
- package/dist/assistant-embed-profile.js +150 -0
- package/dist/assistant-embed-profile.js.map +1 -0
- package/dist/assistant-embed-scaffold-template.d.ts +3 -2
- package/dist/assistant-embed-scaffold-template.d.ts.map +1 -1
- package/dist/assistant-embed-scaffold-template.js +39 -84
- package/dist/assistant-embed-scaffold-template.js.map +1 -1
- package/dist/assistant-embed-tests.d.ts +5 -0
- package/dist/assistant-embed-tests.d.ts.map +1 -0
- package/dist/assistant-embed-tests.js +106 -0
- package/dist/assistant-embed-tests.js.map +1 -0
- package/dist/assistant-embed-vue.d.ts +3 -0
- package/dist/assistant-embed-vue.d.ts.map +1 -0
- package/dist/assistant-embed-vue.js +77 -0
- package/dist/assistant-embed-vue.js.map +1 -0
- package/dist/commands/assistant-embed-ops.d.ts.map +1 -1
- package/dist/commands/assistant-embed-ops.js +112 -63
- package/dist/commands/assistant-embed-ops.js.map +1 -1
- package/dist/commands/author-loop.d.ts.map +1 -1
- package/dist/commands/author-loop.js +24 -28
- package/dist/commands/author-loop.js.map +1 -1
- package/dist/commands/deploy-first-flow.d.ts.map +1 -1
- package/dist/commands/deploy-first-flow.js +26 -15
- package/dist/commands/deploy-first-flow.js.map +1 -1
- package/dist/commands/deploy-preflight.d.ts +5 -0
- package/dist/commands/deploy-preflight.d.ts.map +1 -1
- package/dist/commands/deploy-preflight.js +44 -5
- package/dist/commands/deploy-preflight.js.map +1 -1
- package/dist/commands/local-readiness.d.ts +9 -1
- package/dist/commands/local-readiness.d.ts.map +1 -1
- package/dist/commands/local-readiness.js +74 -4
- package/dist/commands/local-readiness.js.map +1 -1
- package/dist/commands/project-setup.d.ts.map +1 -1
- package/dist/commands/project-setup.js +10 -15
- package/dist/commands/project-setup.js.map +1 -1
- package/dist/control-plane-request.d.ts +4 -0
- package/dist/control-plane-request.d.ts.map +1 -1
- package/dist/control-plane-request.js +40 -20
- package/dist/control-plane-request.js.map +1 -1
- package/dist/project-scaffold-model.d.ts +14 -0
- package/dist/project-scaffold-model.d.ts.map +1 -0
- package/dist/project-scaffold-model.js +36 -0
- package/dist/project-scaffold-model.js.map +1 -0
- package/dist/project-scaffold-templates.d.ts.map +1 -1
- package/dist/project-scaffold-templates.js +73 -39
- package/dist/project-scaffold-templates.js.map +1 -1
- package/dist/project-scaffold-test-template.d.ts +4 -0
- package/dist/project-scaffold-test-template.d.ts.map +1 -0
- package/dist/project-scaffold-test-template.js +89 -0
- package/dist/project-scaffold-test-template.js.map +1 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +1 -2
- package/dist/project.js.map +1 -1
- package/dist/widget-focused-template.d.ts +1 -1
- package/dist/widget-focused-template.d.ts.map +1 -1
- package/dist/widget-focused-template.js +34 -12
- package/dist/widget-focused-template.js.map +1 -1
- package/dist/widget-scaffold-template.d.ts +1 -1
- package/dist/widget-scaffold-template.d.ts.map +1 -1
- package/dist/widget-scaffold-template.js +75 -43
- package/dist/widget-scaffold-template.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +17 -3
- package/node_modules/@noodle-borg/agent-kit/dist/skill-app-playbook-ref.js +2 -2
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +9 -12
- package/node_modules/@noodle-borg/agent-kit/dist/skill-connect-refs.js +2 -2
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-operations-ref.js +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +32 -26
- package/node_modules/@noodle-borg/agent-kit/dist/skill-server-playbook-ref.js +2 -2
- package/node_modules/@noodle-borg/agent-kit/dist/skill-verification-ref.js +2 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
- package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +6 -0
- package/node_modules/@noodle-borg/authoring/dist/recording.d.ts +1 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-assistant.js +10 -4
- package/node_modules/@noodle-borg/compiler/package.json +0 -1
- package/node_modules/@noodle-borg/deploy-client/dist/deploy-payload-size.js +6 -2
- package/node_modules/@noodle-borg/service/dist/registry-helpers.d.ts +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/deploy-preflight.js +193 -96
- package/node_modules/@noodle-borg/service/package.json +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +3 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +3 -0
- package/node_modules/@noodleseed/assistant/README.md +21 -23
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +5 -4
- package/dist/saas-scaffold-template.d.ts +0 -4
- package/dist/saas-scaffold-template.d.ts.map +0 -1
- package/dist/saas-scaffold-template.js +0 -56
- package/dist/saas-scaffold-template.js.map +0 -1
- package/node_modules/tailwindcss/LICENSE +0 -21
- package/node_modules/tailwindcss/README.md +0 -36
- package/node_modules/tailwindcss/dist/chunk-5JIJA4QV.mjs +0 -1
- package/node_modules/tailwindcss/dist/chunk-HMCCH6MG.mjs +0 -1
- package/node_modules/tailwindcss/dist/chunk-X4GG3EDV.mjs +0 -1
- package/node_modules/tailwindcss/dist/colors-C__qRT83.d.ts +0 -347
- package/node_modules/tailwindcss/dist/colors.d.mts +0 -347
- package/node_modules/tailwindcss/dist/colors.d.ts +0 -5
- package/node_modules/tailwindcss/dist/colors.js +0 -1
- package/node_modules/tailwindcss/dist/colors.mjs +0 -1
- package/node_modules/tailwindcss/dist/default-theme.d.mts +0 -1199
- package/node_modules/tailwindcss/dist/default-theme.d.ts +0 -1199
- package/node_modules/tailwindcss/dist/default-theme.js +0 -1
- package/node_modules/tailwindcss/dist/default-theme.mjs +0 -1
- package/node_modules/tailwindcss/dist/flatten-color-palette.d.mts +0 -6
- package/node_modules/tailwindcss/dist/flatten-color-palette.d.ts +0 -6
- package/node_modules/tailwindcss/dist/flatten-color-palette.js +0 -1
- package/node_modules/tailwindcss/dist/flatten-color-palette.mjs +0 -1
- package/node_modules/tailwindcss/dist/lib.d.mts +0 -379
- package/node_modules/tailwindcss/dist/lib.d.ts +0 -3
- package/node_modules/tailwindcss/dist/lib.js +0 -38
- package/node_modules/tailwindcss/dist/lib.mjs +0 -38
- package/node_modules/tailwindcss/dist/plugin.d.mts +0 -11
- package/node_modules/tailwindcss/dist/plugin.d.ts +0 -134
- package/node_modules/tailwindcss/dist/plugin.js +0 -1
- package/node_modules/tailwindcss/dist/plugin.mjs +0 -1
- package/node_modules/tailwindcss/dist/resolve-config-B4yBzhca.d.ts +0 -29
- package/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.mts +0 -190
- package/node_modules/tailwindcss/dist/types-DWdTiksJ.d.mts +0 -128
- package/node_modules/tailwindcss/index.css +0 -944
- package/node_modules/tailwindcss/package.json +0 -89
- package/node_modules/tailwindcss/preflight.css +0 -393
- package/node_modules/tailwindcss/theme.css +0 -510
- package/node_modules/tailwindcss/utilities.css +0 -1
|
@@ -1,14 +1,24 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { cspFaultsInManifest } from '@noodle-borg/compiler';
|
|
2
3
|
import { readDeployBody, sendJson } from '@noodle-borg/transport-http';
|
|
3
|
-
import { deployPreflightRequestSchema, formatWireError } from '@noodle-borg/wire-contracts';
|
|
4
|
+
import { DEPLOY_PREFLIGHT_CHECK_TIMEOUT_MS, deployPreflightRequestSchema, formatWireError, } from '@noodle-borg/wire-contracts';
|
|
4
5
|
import { manifestUsesUserRoot } from '../registry-access.js';
|
|
5
6
|
import { isIdentityAccessMode } from './access-mode.js';
|
|
6
7
|
import { authorizeDeploymentOwnerSelection, authorizeTenantControl, developerGrantRouteAccess, } from './control-plane.js';
|
|
8
|
+
// Per-process resource admission, not a tenant quota or distributed state authority.
|
|
9
|
+
const activePreflights = new WeakSet();
|
|
7
10
|
/**
|
|
8
11
|
* Read-only first-deploy readiness. It intentionally does not verify uploaded asset bytes:
|
|
9
12
|
* the CLI calls this before it requests upload targets or sends any bytes.
|
|
10
13
|
*/
|
|
11
14
|
export async function handleDeployPreflight(req, res, registry, options, maxBody, tenant, gate, controlPlane, audit) {
|
|
15
|
+
const startedAt = Date.now();
|
|
16
|
+
const suppliedId = req.headers['x-request-id'];
|
|
17
|
+
const requestId = typeof suppliedId === 'string' &&
|
|
18
|
+
/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(suppliedId)
|
|
19
|
+
? suppliedId
|
|
20
|
+
: randomUUID();
|
|
21
|
+
res.setHeader('x-request-id', requestId);
|
|
12
22
|
const identity = await authorizeTenantControl(req, res, gate, controlPlane, tenant.org, developerGrantRouteAccess(options.developerGrantStore, 'deployments:write'));
|
|
13
23
|
if (identity === false)
|
|
14
24
|
return;
|
|
@@ -25,111 +35,198 @@ export async function handleDeployPreflight(req, res, registry, options, maxBody
|
|
|
25
35
|
error: 'app is archived; restore it before deploying',
|
|
26
36
|
});
|
|
27
37
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
parsed = result.data;
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
return sendJson(res, 400, {
|
|
41
|
-
code: 'invalid_deploy_request',
|
|
42
|
-
error: `invalid deploy preflight request: ${error.message}`,
|
|
38
|
+
if (activePreflights.has(registry)) {
|
|
39
|
+
await audit.emit({
|
|
40
|
+
eventType: 'deploy.preflight.rejected',
|
|
41
|
+
...tenant,
|
|
42
|
+
actorSubject: identity.subject,
|
|
43
|
+
decision: 'deny',
|
|
44
|
+
status: 503,
|
|
45
|
+
reasonCode: 'deploy_preflight_busy',
|
|
46
|
+
details: { requestId, phase: 'admission', elapsedMs: Date.now() - startedAt },
|
|
43
47
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
error: `${accessMode} deployments require an authenticated deployer`,
|
|
48
|
+
res.setHeader('retry-after', '5');
|
|
49
|
+
return sendJson(res, 503, {
|
|
50
|
+
code: 'deploy_preflight_busy',
|
|
51
|
+
phase: 'admission',
|
|
52
|
+
error: 'This instance is already checking a deployment. Retry once after the indicated delay.',
|
|
50
53
|
});
|
|
51
54
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
activePreflights.add(registry);
|
|
56
|
+
let clientDisconnected = false;
|
|
57
|
+
let deadlineExceeded = false;
|
|
58
|
+
let phase = 'body';
|
|
59
|
+
let timer;
|
|
60
|
+
const onClose = () => {
|
|
61
|
+
if (!res.writableFinished)
|
|
62
|
+
clientDisconnected = true;
|
|
63
|
+
};
|
|
64
|
+
res.once('close', onClose);
|
|
65
|
+
try {
|
|
66
|
+
await audit.emit({
|
|
67
|
+
eventType: 'deploy.preflight.started',
|
|
68
|
+
...tenant,
|
|
69
|
+
actorSubject: identity.subject,
|
|
70
|
+
decision: 'allow',
|
|
71
|
+
details: { requestId, phase, elapsedMs: Date.now() - startedAt },
|
|
59
72
|
});
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
const body = await readDeployBody(req, maxBody);
|
|
74
|
+
if (req.aborted || res.destroyed)
|
|
75
|
+
return;
|
|
76
|
+
if (!body.ok)
|
|
77
|
+
return sendJson(res, body.status, { error: body.error });
|
|
78
|
+
phase = 'validation';
|
|
79
|
+
let parsed;
|
|
80
|
+
try {
|
|
81
|
+
const raw = JSON.parse(body.text);
|
|
82
|
+
const result = deployPreflightRequestSchema.safeParse(raw);
|
|
83
|
+
if (!result.success)
|
|
84
|
+
throw new Error(formatWireError(result.error));
|
|
85
|
+
parsed = result.data;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return sendJson(res, 400, {
|
|
89
|
+
code: 'invalid_deploy_request',
|
|
90
|
+
error: `invalid deploy preflight request: ${error.message}`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const accessMode = parsed.accessMode ?? 'owner-only';
|
|
94
|
+
if (isIdentityAccessMode(accessMode) && identity === undefined) {
|
|
95
|
+
return sendJson(res, 401, {
|
|
96
|
+
code: 'deployer_identity_required',
|
|
97
|
+
error: `${accessMode} deployments require an authenticated deployer`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const ownerSelection = await authorizeDeploymentOwnerSelection(res, controlPlane, tenant.org, accessMode, identity, parsed.ownerSubject);
|
|
101
|
+
if (!ownerSelection.ok)
|
|
102
|
+
return;
|
|
103
|
+
if (accessMode === 'public' && manifestUsesUserRoot(parsed.manifest)) {
|
|
104
|
+
return sendJson(res, 400, {
|
|
105
|
+
code: 'public_user_context_conflict',
|
|
106
|
+
error: 'public access mode cannot reference ${user}; use mixed for optional identity',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const [cspFault] = cspFaultsInManifest(parsed.manifest);
|
|
110
|
+
if (cspFault !== undefined) {
|
|
111
|
+
return sendJson(res, 400, {
|
|
112
|
+
code: 'invalid_widget_csp',
|
|
113
|
+
error: `widget "${cspFault.widget}" CSP ${cspFault.list} origin "${cspFault.value}" is not an ` +
|
|
114
|
+
`absolute https:// origin and would be dropped by the host renderer` +
|
|
115
|
+
(cspFault.suggestion !== undefined ? `; use "${cspFault.suggestion}"` : ''),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
phase = 'checks';
|
|
119
|
+
timer = setTimeout(() => {
|
|
120
|
+
deadlineExceeded = true;
|
|
121
|
+
if (!res.headersSent && !res.destroyed)
|
|
122
|
+
sendJson(res, 504, {
|
|
123
|
+
code: 'deploy_preflight_timeout',
|
|
124
|
+
phase,
|
|
125
|
+
error: `Preflight exceeded its ${DEPLOY_PREFLIGHT_CHECK_TIMEOUT_MS}ms checking budget. Publication did not start.`,
|
|
126
|
+
});
|
|
127
|
+
}, DEPLOY_PREFLIGHT_CHECK_TIMEOUT_MS);
|
|
128
|
+
const pending = [
|
|
129
|
+
registry.getApp(tenant.org, tenant.app),
|
|
130
|
+
registry.getEnvironment(tenant.org, tenant.app, tenant.env),
|
|
131
|
+
registry.preflightDeploy(tenant, parsed.manifest, {
|
|
132
|
+
...(parsed.connectors !== undefined ? { connectors: parsed.connectors } : {}),
|
|
133
|
+
actor: identity,
|
|
134
|
+
accessMode,
|
|
135
|
+
ownerSubject: ownerSelection.ownerSubject,
|
|
136
|
+
...(parsed.orgMembershipSources !== undefined
|
|
137
|
+
? { orgMembershipSources: parsed.orgMembershipSources }
|
|
138
|
+
: {}),
|
|
139
|
+
...(parsed.hostedAssets !== undefined ? { hostedAssets: parsed.hostedAssets } : {}),
|
|
140
|
+
...(parsed.serverVersion !== undefined ? { serverVersion: parsed.serverVersion } : {}),
|
|
141
|
+
deploymentSource: parsed.deploymentSource ?? 'cli',
|
|
142
|
+
}),
|
|
143
|
+
];
|
|
144
|
+
const checked = await Promise.all(pending)
|
|
145
|
+
.catch(async (error) => {
|
|
146
|
+
// Keep the resource slot until every already-started check settles, including after a timeout.
|
|
147
|
+
await Promise.allSettled(pending);
|
|
148
|
+
throw error;
|
|
149
|
+
})
|
|
150
|
+
.finally(() => clearTimeout(timer));
|
|
151
|
+
const [application, environment, preflight] = checked;
|
|
152
|
+
const errors = preflight.ok ? [] : preflight.errors;
|
|
153
|
+
const missingSecrets = configNames(errors, 'missing_secret', 'secrets.');
|
|
154
|
+
const missingVariables = configNames(errors, 'missing_variable', 'variables.');
|
|
155
|
+
const appState = application === undefined ? 'will-create' : 'existing';
|
|
156
|
+
const environmentState = environment === undefined ? 'will-create' : 'existing';
|
|
157
|
+
const ready = errors.length === 0;
|
|
158
|
+
const codes = [...new Set(errors.map((error) => error.code))].sort().join(',');
|
|
159
|
+
await audit.emit({
|
|
160
|
+
eventType: 'deploy.preflight.checked',
|
|
161
|
+
org: tenant.org,
|
|
162
|
+
app: tenant.app,
|
|
163
|
+
env: tenant.env,
|
|
164
|
+
decision: 'allow',
|
|
165
|
+
status: 200,
|
|
166
|
+
actorSubject: identity.subject,
|
|
167
|
+
...(identity.email !== undefined ? { actorEmail: identity.email } : {}),
|
|
168
|
+
details: {
|
|
169
|
+
requestId,
|
|
170
|
+
phase,
|
|
171
|
+
elapsedMs: Date.now() - startedAt,
|
|
172
|
+
clientDisconnected,
|
|
173
|
+
deadlineExceeded,
|
|
174
|
+
ready,
|
|
175
|
+
appState,
|
|
176
|
+
environmentState,
|
|
177
|
+
...(ownerSelection.ownerSubject !== undefined
|
|
178
|
+
? { ownerSubject: ownerSelection.ownerSubject }
|
|
179
|
+
: {}),
|
|
180
|
+
errorCount: errors.length,
|
|
181
|
+
codes,
|
|
182
|
+
missingSecretCount: missingSecrets.length,
|
|
183
|
+
missingVariableCount: missingVariables.length,
|
|
184
|
+
},
|
|
68
185
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
registry.preflightDeploy(tenant, parsed.manifest, {
|
|
74
|
-
...(parsed.connectors !== undefined ? { connectors: parsed.connectors } : {}),
|
|
75
|
-
actor: identity,
|
|
76
|
-
accessMode,
|
|
77
|
-
ownerSubject: ownerSelection.ownerSubject,
|
|
78
|
-
...(parsed.orgMembershipSources !== undefined
|
|
79
|
-
? { orgMembershipSources: parsed.orgMembershipSources }
|
|
80
|
-
: {}),
|
|
81
|
-
...(parsed.hostedAssets !== undefined ? { hostedAssets: parsed.hostedAssets } : {}),
|
|
82
|
-
...(parsed.serverVersion !== undefined ? { serverVersion: parsed.serverVersion } : {}),
|
|
83
|
-
deploymentSource: parsed.deploymentSource ?? 'cli',
|
|
84
|
-
}),
|
|
85
|
-
]);
|
|
86
|
-
const errors = preflight.ok ? [] : preflight.errors;
|
|
87
|
-
const missingSecrets = configNames(errors, 'missing_secret', 'secrets.');
|
|
88
|
-
const missingVariables = configNames(errors, 'missing_variable', 'variables.');
|
|
89
|
-
const appState = application === undefined ? 'will-create' : 'existing';
|
|
90
|
-
const environmentState = environment === undefined ? 'will-create' : 'existing';
|
|
91
|
-
const ready = errors.length === 0;
|
|
92
|
-
const codes = [...new Set(errors.map((error) => error.code))].sort().join(',');
|
|
93
|
-
await audit.emit({
|
|
94
|
-
eventType: 'deploy.preflight.checked',
|
|
95
|
-
org: tenant.org,
|
|
96
|
-
app: tenant.app,
|
|
97
|
-
env: tenant.env,
|
|
98
|
-
decision: 'allow',
|
|
99
|
-
status: 200,
|
|
100
|
-
actorSubject: identity.subject,
|
|
101
|
-
...(identity.email !== undefined ? { actorEmail: identity.email } : {}),
|
|
102
|
-
details: {
|
|
186
|
+
if (deadlineExceeded || clientDisconnected || res.destroyed)
|
|
187
|
+
return;
|
|
188
|
+
return sendJson(res, 200, {
|
|
189
|
+
ok: true,
|
|
103
190
|
ready,
|
|
104
|
-
appState,
|
|
105
|
-
environmentState,
|
|
106
191
|
...(ownerSelection.ownerSubject !== undefined
|
|
107
192
|
? { ownerSubject: ownerSelection.ownerSubject }
|
|
108
193
|
: {}),
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
194
|
+
target: {
|
|
195
|
+
...tenant,
|
|
196
|
+
appState,
|
|
197
|
+
environmentState,
|
|
198
|
+
},
|
|
199
|
+
config: {
|
|
200
|
+
ready: missingSecrets.length === 0 && missingVariables.length === 0,
|
|
201
|
+
missingSecrets,
|
|
202
|
+
missingVariables,
|
|
203
|
+
},
|
|
204
|
+
errors,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
await audit.emit({
|
|
209
|
+
eventType: 'deploy.preflight.failed',
|
|
122
210
|
...tenant,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
211
|
+
actorSubject: identity.subject,
|
|
212
|
+
decision: 'deny',
|
|
213
|
+
status: res.headersSent ? res.statusCode : 500,
|
|
214
|
+
reasonCode: 'preflight_failed',
|
|
215
|
+
details: {
|
|
216
|
+
requestId,
|
|
217
|
+
phase,
|
|
218
|
+
elapsedMs: Date.now() - startedAt,
|
|
219
|
+
clientDisconnected,
|
|
220
|
+
deadlineExceeded,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
clearTimeout(timer);
|
|
227
|
+
res.removeListener('close', onClose);
|
|
228
|
+
activePreflights.delete(registry);
|
|
229
|
+
}
|
|
133
230
|
}
|
|
134
231
|
function configNames(errors, code, prefix) {
|
|
135
232
|
return [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
41
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
42
|
-
"@noodle-borg/agent-kit": "0.
|
|
42
|
+
"@noodle-borg/agent-kit": "0.95.0",
|
|
43
43
|
"@noodle-borg/app-package": "0.0.0",
|
|
44
44
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
45
45
|
"@noodle-borg/auth": "0.0.0",
|
|
@@ -137,6 +137,9 @@ export declare const deployErrorResponseSchema: z.ZodObject<{
|
|
|
137
137
|
errors: z.ZodOptional<z.ZodUnknown>;
|
|
138
138
|
}, z.core.$strip>;
|
|
139
139
|
export type DeployErrorResponse = z.infer<typeof deployErrorResponseSchema>;
|
|
140
|
+
/** Checking budget after upload/authorization; the client allows additional upload/response time. */
|
|
141
|
+
export declare const DEPLOY_PREFLIGHT_CHECK_TIMEOUT_MS = 60000;
|
|
142
|
+
export declare const DEPLOY_PREFLIGHT_CLIENT_TIMEOUT_MS = 75000;
|
|
140
143
|
/**
|
|
141
144
|
* `POST /v1/orgs/{org}/apps/{app}/envs/{env}/deploy/preflight` accepts the same
|
|
142
145
|
* declarative input as deploy, but performs no deployment or asset upload.
|
|
@@ -109,6 +109,9 @@ export const deployErrorResponseSchema = z.object({
|
|
|
109
109
|
errors: z.unknown().optional(),
|
|
110
110
|
});
|
|
111
111
|
// ─── Deploy preflight ─────────────────────────────────────────────────────────────
|
|
112
|
+
/** Checking budget after upload/authorization; the client allows additional upload/response time. */
|
|
113
|
+
export const DEPLOY_PREFLIGHT_CHECK_TIMEOUT_MS = 60_000;
|
|
114
|
+
export const DEPLOY_PREFLIGHT_CLIENT_TIMEOUT_MS = 75_000;
|
|
112
115
|
/**
|
|
113
116
|
* `POST /v1/orgs/{org}/apps/{app}/envs/{env}/deploy/preflight` accepts the same
|
|
114
117
|
* declarative input as deploy, but performs no deployment or asset upload.
|
|
@@ -6,7 +6,8 @@ The package exports the canonical `<noodle-assistant>` managed Web Component, th
|
|
|
6
6
|
`<noodle-app-view>` MCP App host from `@noodleseed/assistant/app-view`, a managed React wrapper and
|
|
7
7
|
`NoodleAppView` adapter from `@noodleseed/assistant/react`, a renderer-free React hook from
|
|
8
8
|
`@noodleseed/assistant/react/client`, a DOM-free client from `@noodleseed/assistant/client`, and the
|
|
9
|
-
backend-only `
|
|
9
|
+
backend-only `createAssistantSessionHandler` and lower-level `createAssistantSession` exchange from
|
|
10
|
+
`@noodleseed/assistant/server`. The component inherits the
|
|
10
11
|
deployed MCP server's brand kit while slots, methods, events, and semantic CSS variables let a SaaS developer
|
|
11
12
|
integrate it without depending on internal DOM selectors. Light, dark, automatic host-page matching, and
|
|
12
13
|
host-page inversion work without replacing conversation or App DOM.
|
|
@@ -193,32 +194,29 @@ noodle assistant clients create --name web --org acme --app support --env prod
|
|
|
193
194
|
|
|
194
195
|
The command saves `{ clientId, clientSecret }` to a mode-`0600` file and prints its path, never the secret.
|
|
195
196
|
Move those values to the customer backend's secret manager without printing or committing them. A framework
|
|
196
|
-
route can
|
|
197
|
+
route can use the maintained same-origin handler. Generate the route, authentication adapter, mount and
|
|
198
|
+
contract tests with `noodle assistant embed --framework nextjs --surface authenticated` in the existing
|
|
199
|
+
application. Implement only `authenticateAssistantRequest` using its existing session and membership checks:
|
|
197
200
|
|
|
198
201
|
```ts
|
|
199
|
-
import {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
user: {
|
|
210
|
-
id: user.id,
|
|
211
|
-
email: user.email,
|
|
212
|
-
roles: user.roles,
|
|
213
|
-
scopes: user.scopes,
|
|
214
|
-
},
|
|
215
|
-
context,
|
|
216
|
-
preferences: { locale: user.locale, timeZone: user.timeZone },
|
|
217
|
-
});
|
|
218
|
-
return Response.json(session);
|
|
219
|
-
}
|
|
202
|
+
import { createAssistantSessionHandler } from "@noodleseed/assistant/server";
|
|
203
|
+
import { authenticateAssistantRequest } from "../../../../lib/noodle-assistant-auth";
|
|
204
|
+
|
|
205
|
+
export const POST = createAssistantSessionHandler({
|
|
206
|
+
serviceUrl: process.env.NOODLE_SERVICE_URL,
|
|
207
|
+
clientId: process.env.NOODLE_ASSISTANT_CLIENT_ID,
|
|
208
|
+
clientSecret: process.env.NOODLE_ASSISTANT_CLIENT_SECRET,
|
|
209
|
+
origin: process.env.PUBLIC_APP_ORIGIN,
|
|
210
|
+
authenticate: authenticateAssistantRequest,
|
|
211
|
+
});
|
|
220
212
|
```
|
|
221
213
|
|
|
214
|
+
The handler owns exact-Origin and JSON checks, signed-out JSON 401, bounded context/body parsing, no-store
|
|
215
|
+
responses, a 15-second deadline, and sanitized exchange failures without retries or redirects. Your adapter
|
|
216
|
+
returns `AssistantSessionIdentity | null`; its `user`, claims, preferences and routing must be backend-verified.
|
|
217
|
+
Keep stricter application CSRF middleware. Run the generated contract suite and your real identity/tenant
|
|
218
|
+
acceptance tests; synthetic contract tests alone do not verify your login implementation.
|
|
219
|
+
|
|
222
220
|
For a connector that uses `customerEndpoint("customer_api", ...)`, the authenticated backend may also pass
|
|
223
221
|
`routing: { endpoints: { customer_api: account.clusterApiBaseUrl } }`. Resolve the URL from server-owned
|
|
224
222
|
user/account membership after authentication; never accept it from the browser, page context, session
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/assistant",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.0",
|
|
4
4
|
"description": "Embed the Noodle Seed customer-branded assistant in your web app with managed or framework-owned UI, a framework-neutral MCP App host, a DOM-free client, and a backend session helper. Authoring and deploying the server is @noodleseed/one.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/one",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.157.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -205,7 +205,6 @@
|
|
|
205
205
|
"shebang-command",
|
|
206
206
|
"shebang-regex",
|
|
207
207
|
"statuses",
|
|
208
|
-
"tailwindcss",
|
|
209
208
|
"tldts",
|
|
210
209
|
"tldts-core",
|
|
211
210
|
"toidentifier",
|
|
@@ -236,7 +235,7 @@
|
|
|
236
235
|
"@modelcontextprotocol/client": "2.0.0",
|
|
237
236
|
"@modelcontextprotocol/server": "2.0.0",
|
|
238
237
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
239
|
-
"@noodle-borg/agent-kit": "0.
|
|
238
|
+
"@noodle-borg/agent-kit": "0.95.0",
|
|
240
239
|
"@noodle-borg/app-audit": "0.0.0",
|
|
241
240
|
"@noodle-borg/app-package": "0.0.0",
|
|
242
241
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
@@ -285,7 +284,9 @@
|
|
|
285
284
|
"zod-to-json-schema": "3.25.2"
|
|
286
285
|
},
|
|
287
286
|
"devDependencies": {
|
|
288
|
-
"@
|
|
287
|
+
"@noodleseed/assistant": "@noodleseed/assistant@file:///home/runner/work/noodle-borg/noodle-borg/packages/assistant",
|
|
288
|
+
"@types/node": "24.13.1",
|
|
289
|
+
"next": "16.2.9"
|
|
289
290
|
},
|
|
290
291
|
"optionalDependencies": {}
|
|
291
292
|
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ProjectAgentTarget } from './project.js';
|
|
2
|
-
/** Default SaaS starter: the portable Apps surface plus customer identity and verified context. */
|
|
3
|
-
export declare function saasFiles(name: string, agentTargets: readonly ProjectAgentTarget[]): Record<string, string>;
|
|
4
|
-
//# sourceMappingURL=saas-scaffold-template.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"saas-scaffold-template.d.ts","sourceRoot":"","sources":["../src/saas-scaffold-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD,mGAAmG;AACnG,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,SAAS,kBAAkB,EAAE,GAC1C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6DxB"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { widgetFiles } from './widget-scaffold-template.js';
|
|
2
|
-
/** Default SaaS starter: the portable Apps surface plus customer identity and verified context. */
|
|
3
|
-
export function saasFiles(name, agentTargets) {
|
|
4
|
-
const files = widgetFiles(name, agentTargets);
|
|
5
|
-
const server = files['src/server.ts'];
|
|
6
|
-
const config = files['noodle.json'];
|
|
7
|
-
if (server === undefined || config === undefined)
|
|
8
|
-
throw new Error('SaaS template source is incomplete');
|
|
9
|
-
return {
|
|
10
|
-
...files,
|
|
11
|
-
'noodle.json': config.replace('"template": "widget"', '"template": "saas"'),
|
|
12
|
-
'src/server.ts': server
|
|
13
|
-
.replace(' annotations,\n', ' annotations,\n customerAuth,\n')
|
|
14
|
-
.replace(" instructions: 'Help users understand their workspace, update preferences, and plan a safe next step.',", ` instructions: 'Help users understand their workspace, update preferences, and plan a safe next step.',
|
|
15
|
-
// Replace these placeholders with the customer IdP values used by ChatGPT, Claude, and your app.
|
|
16
|
-
auth: customerAuth.federatedOidc({
|
|
17
|
-
issuers: [{
|
|
18
|
-
issuer: 'https://id.your-app.example.com',
|
|
19
|
-
audience: 'https://your-noodle-mcp.example.com/mcp',
|
|
20
|
-
}],
|
|
21
|
-
}),`)
|
|
22
|
-
.replace("description: 'List the current workspace items with concise status summaries.',", "description: 'List the current workspace items with concise status summaries.',\n contextProvider: true,")
|
|
23
|
-
.replace("input: z.object({ status: z.enum(['all', 'active', 'done']).default('all').meta({ title: 'Status' }) }),", 'input: z.object({}),'),
|
|
24
|
-
'README.md': `${files['README.md'] ?? ''}
|
|
25
|
-
|
|
26
|
-
## Customer identity and delegated APIs
|
|
27
|
-
|
|
28
|
-
The default server uses standards-based federated OIDC so the same MCP endpoint works from remote MCP clients
|
|
29
|
-
and any embedded assistant that you explicitly configure. Your application team owns the authorization server; Noodle verifies its tokens
|
|
30
|
-
but does not add OAuth discovery or registration endpoints in front of it.
|
|
31
|
-
|
|
32
|
-
For every direct or federated issuer, publish all of the following:
|
|
33
|
-
|
|
34
|
-
- The path-inserted RFC 8414 metadata URL as direct, unauthenticated HTTP 200 JSON. For issuer
|
|
35
|
-
\`https://id.example.com/oauth\`, that URL is
|
|
36
|
-
\`https://id.example.com/.well-known/oauth-authorization-server/oauth\`.
|
|
37
|
-
- HTTPS \`authorization_endpoint\`, \`token_endpoint\`, \`jwks_uri\`, and RFC 7591
|
|
38
|
-
\`registration_endpoint\` values in that metadata.
|
|
39
|
-
- Authorization code and refresh-token grants, PKCE \`S256\`, and public clients by advertising
|
|
40
|
-
\`code_challenge_methods_supported: ["S256"]\` and
|
|
41
|
-
\`token_endpoint_auth_methods_supported: ["none"]\`.
|
|
42
|
-
- RFC 8707 \`resource\` handling: validate the exact URL on authorize, code exchange, and refresh, then
|
|
43
|
-
map each approved MCP resource to the stable app/environment audience configured in \`customerAuth\`.
|
|
44
|
-
- A public JWKS containing only public signing keys.
|
|
45
|
-
|
|
46
|
-
Run \`noodle auth doctor src/server.ts\` before sharing the endpoint. The doctor is read-only: it verifies
|
|
47
|
-
discovery, metadata, capabilities, and JWKS without registering a client.
|
|
48
|
-
|
|
49
|
-
Verified OIDC callers are classified as customers by the runtime; never add a caller-controlled identity
|
|
50
|
-
classification claim. For a customer-owned API, declare connector auth as \`delegatedTokenExchange\` and
|
|
51
|
-
store its client credential with \`noodle secrets set\`. Use \`noodle auth doctor --live\` before release to
|
|
52
|
-
exercise one credential exchange without invoking a business tool.
|
|
53
|
-
`,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=saas-scaffold-template.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"saas-scaffold-template.js","sourceRoot":"","sources":["../src/saas-scaffold-template.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,mGAAmG;AACnG,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,YAA2C;IAE3C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAC9C,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,OAAO;QACL,GAAG,KAAK;QACR,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,oBAAoB,CAAC;QAC3E,eAAe,EAAE,MAAM;aACpB,OAAO,CAAC,kBAAkB,EAAE,mCAAmC,CAAC;aAChE,OAAO,CACN,0GAA0G,EAC1G;;;;;;;MAOF,CACC;aACA,OAAO,CACN,iFAAiF,EACjF,6GAA6G,CAC9G;aACA,OAAO,CACN,0GAA0G,EAC1G,sBAAsB,CACvB;QACH,WAAW,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B3C;KACE,CAAC;AACJ,CAAC"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) Tailwind Labs, Inc.
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<a href="https://tailwindcss.com" target="_blank">
|
|
3
|
-
<picture>
|
|
4
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-dark.svg">
|
|
5
|
-
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg">
|
|
6
|
-
<img alt="Tailwind CSS" src="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg" width="350" height="70" style="max-width: 100%;">
|
|
7
|
-
</picture>
|
|
8
|
-
</a>
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
<p align="center">
|
|
12
|
-
A utility-first CSS framework for rapidly building custom user interfaces.
|
|
13
|
-
</p>
|
|
14
|
-
|
|
15
|
-
<p align="center">
|
|
16
|
-
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci.yml?branch=main" alt="Build Status"></a>
|
|
17
|
-
<a href="https://www.npmjs.com/package/tailwindcss"><img src="https://img.shields.io/npm/dt/tailwindcss.svg" alt="Total Downloads"></a>
|
|
18
|
-
<a href="https://github.com/tailwindlabs/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
|
|
19
|
-
<a href="https://github.com/tailwindlabs/tailwindcss/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
|
|
20
|
-
</p>
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Documentation
|
|
25
|
-
|
|
26
|
-
For full documentation, visit [tailwindcss.com](https://tailwindcss.com).
|
|
27
|
-
|
|
28
|
-
## Community
|
|
29
|
-
|
|
30
|
-
For help, discussion about best practices, or feature ideas:
|
|
31
|
-
|
|
32
|
-
[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions)
|
|
33
|
-
|
|
34
|
-
## Contributing
|
|
35
|
-
|
|
36
|
-
If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function h(n){if(arguments.length===0)throw new TypeError("`CSS.escape` requires an argument.");let e=String(n),i=e.length,r=-1,t,s="",l=e.charCodeAt(0);if(i===1&&l===45)return"\\"+e;for(;++r<i;){if(t=e.charCodeAt(r),t===0){s+="\uFFFD";continue}if(t>=1&&t<=31||t===127||r===0&&t>=48&&t<=57||r===1&&t>=48&&t<=57&&l===45){s+="\\"+t.toString(16)+" ";continue}if(t>=128||t===45||t===95||t>=48&&t<=57||t>=65&&t<=90||t>=97&&t<=122){s+=e.charAt(r);continue}s+="\\"+e.charAt(r)}return s}function a(n){return n.replace(/\\([\dA-Fa-f]{1,6}[\t\n\f\r ]?|[\S\s])/g,e=>{if(e.length<=2)return e[1];let i=Number.parseInt(e.slice(1).trim(),16);return i===0||i>1114111||i>=55296&&i<=57343?"\uFFFD":String.fromCodePoint(i)})}var c=new Map([["--font",["--font-weight","--font-size"]],["--inset",["--inset-shadow","--inset-ring"]],["--text",["--text-color","--text-decoration-color","--text-decoration-thickness","--text-indent","--text-shadow","--text-underline-offset"]],["--grid-column",["--grid-column-start","--grid-column-end"]],["--grid-row",["--grid-row-start","--grid-row-end"]]]);function g(n,e){return(c.get(e)??[]).some(i=>n===i||n.startsWith(`${i}-`))}var p=class{constructor(e=new Map,i=new Set([])){this.values=e;this.keyframes=i}values;keyframes;prefix=null;get size(){return this.values.size}add(e,i,r=0,t){if(e.endsWith("-*")){if(i!=="initial")throw new Error(`Invalid theme value \`${i}\` for namespace \`${e}\``);e==="--*"?this.values.clear():this.clearNamespace(e.slice(0,-2),0)}if(r&4){let s=this.values.get(e);if(s&&!(s.options&4))return}i==="initial"?this.values.delete(e):this.values.set(e,{value:i,options:r,src:t})}keysInNamespaces(e){let i=[];for(let r of e){let t=`${r}-`;for(let s of this.values.keys())s.startsWith(t)&&s.indexOf("--",2)===-1&&(g(s,r)||i.push(s.slice(t.length)))}return i}get(e){for(let i of e){let r=this.values.get(i);if(r)return r.value}return null}hasDefault(e){return(this.getOptions(e)&4)===4}getOptions(e){return e=a(this.#i(e)),this.values.get(e)?.options??0}entries(){return this.prefix?Array.from(this.values,e=>(e[0]=this.prefixKey(e[0]),e)):this.values.entries()}prefixKey(e){return this.prefix?`--${this.prefix}-${e.slice(2)}`:e}#i(e){return this.prefix?`--${e.slice(3+this.prefix.length)}`:e}clearNamespace(e,i){let r=c.get(e)??[];e:for(let t of this.values.keys())if(t.startsWith(e)){if(i!==0&&(this.getOptions(t)&i)!==i)continue;for(let s of r)if(t.startsWith(s))continue e;this.values.delete(t)}}#e(e,i){for(let r of i){let t=e!==null?`${r}-${e}`:r;if(!this.values.has(t))if(e!==null&&e.includes(".")){if(t=`${r}-${e.replaceAll(".","_")}`,!this.values.has(t))continue}else continue;if(!g(t,r))return t}return null}#t(e){let i=this.values.get(e);if(!i)return null;let r=null;return i.options&2&&(r=i.value),`var(${h(this.prefixKey(e))}${r?`, ${r}`:""})`}markUsedVariable(e){let i=a(this.#i(e)),r=this.values.get(i);if(!r)return!1;let t=r.options&16;return r.options|=16,!t}resolve(e,i,r=0){let t=this.#e(e,i);if(!t)return null;let s=this.values.get(t);return(r|s.options)&1?s.value:this.#t(t)}resolveValue(e,i){let r=this.#e(e,i);return r?this.values.get(r).value:null}resolveWith(e,i,r=[]){let t=this.#e(e,i);if(!t)return null;let s={};for(let u of r){let f=`${t}${u}`,o=this.values.get(f);o&&(o.options&1?s[u]=o.value:s[u]=this.#t(f))}let l=this.values.get(t);return l.options&1?[l.value,s]:[this.#t(t),s]}namespace(e){let i=new Map,r=`${e}-`;for(let[t,s]of this.values)t===e?i.set(null,s.value):t.startsWith(`${r}-`)?i.set(t.slice(e.length),s.value):t.startsWith(r)&&i.set(t.slice(r.length),s.value);return i}addKeyframes(e){this.keyframes.add(e)}getKeyframes(){return Array.from(this.keyframes)}};export{h as a,a as b,p as c};
|