@sequenceholdings/artifact-studio 0.2.5 → 0.3.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.
Files changed (187) hide show
  1. package/README.md +35 -0
  2. package/VERSION-PIN.md +14 -3
  3. package/dist/api.d.ts +11 -1
  4. package/dist/api.js +26 -9
  5. package/dist/atlas-ui-css-plugin.d.ts +11 -7
  6. package/dist/atlas-ui-css-plugin.js +38 -10
  7. package/dist/build.d.ts +2 -2
  8. package/dist/build.js +14 -6
  9. package/dist/cli.d.ts +1 -1
  10. package/dist/cli.js +108 -37
  11. package/dist/dev-link.d.ts +1 -1
  12. package/dist/dev-link.js +2 -1
  13. package/dist/gateway/admission.d.ts +55 -0
  14. package/dist/gateway/admission.js +132 -0
  15. package/dist/gateway/control.d.ts +91 -0
  16. package/dist/gateway/control.js +113 -0
  17. package/dist/gateway/hosted-proxy.d.ts +36 -0
  18. package/dist/gateway/hosted-proxy.js +347 -0
  19. package/dist/gateway/release-admission.d.ts +23 -0
  20. package/dist/gateway/release-admission.js +259 -0
  21. package/dist/gateway/server.d.ts +29 -0
  22. package/dist/gateway/server.js +298 -0
  23. package/dist/gateway/session.d.ts +71 -0
  24. package/dist/gateway/session.js +143 -0
  25. package/dist/gateway/usage.d.ts +37 -0
  26. package/dist/gateway/usage.js +46 -0
  27. package/dist/gateway-main.d.ts +1 -0
  28. package/dist/gateway-main.js +84 -0
  29. package/dist/git-clone.d.ts +23 -1
  30. package/dist/git-clone.js +32 -15
  31. package/dist/manifest-next.d.ts +217 -0
  32. package/dist/manifest-next.js +120 -0
  33. package/dist/manifest-static.d.ts +76 -0
  34. package/dist/manifest-static.js +124 -0
  35. package/dist/manifest.d.ts +124 -19
  36. package/dist/manifest.js +12 -118
  37. package/dist/next/bridge.d.ts +47 -0
  38. package/dist/next/bridge.js +229 -0
  39. package/dist/next/browser-logs.d.ts +7 -0
  40. package/dist/next/browser-logs.js +51 -0
  41. package/dist/next/browser.d.ts +6 -0
  42. package/dist/next/browser.js +57 -0
  43. package/dist/next/protocol.d.ts +73 -0
  44. package/dist/next/protocol.js +56 -0
  45. package/dist/next/release.d.ts +15 -0
  46. package/dist/next/release.js +46 -0
  47. package/dist/next/requests.d.ts +15 -0
  48. package/dist/next/requests.js +59 -0
  49. package/dist/next/routes.d.ts +4 -0
  50. package/dist/next/routes.js +21 -0
  51. package/dist/next/streams.d.ts +16 -0
  52. package/dist/next/streams.js +132 -0
  53. package/dist/next/theme.d.ts +10 -0
  54. package/dist/next/theme.js +45 -0
  55. package/dist/next/transport.d.ts +15 -0
  56. package/dist/next/transport.js +13 -0
  57. package/dist/next-build.d.ts +29 -0
  58. package/dist/next-build.js +129 -0
  59. package/dist/next-cache/adapter-runtime.d.ts +51 -0
  60. package/dist/next-cache/adapter-runtime.js +73 -0
  61. package/dist/next-cache/component-handler.d.ts +3 -0
  62. package/dist/next-cache/component-handler.js +10 -0
  63. package/dist/next-cache/components.d.ts +20 -0
  64. package/dist/next-cache/components.js +113 -0
  65. package/dist/next-cache/config.d.ts +9 -0
  66. package/dist/next-cache/config.js +78 -0
  67. package/dist/next-cache/incremental-handler.d.ts +18 -0
  68. package/dist/next-cache/incremental-handler.js +17 -0
  69. package/dist/next-cache/incremental.d.ts +27 -0
  70. package/dist/next-cache/incremental.js +99 -0
  71. package/dist/next-cache/index.d.ts +18 -0
  72. package/dist/next-cache/index.js +16 -0
  73. package/dist/next-cache/memory-store.d.ts +27 -0
  74. package/dist/next-cache/memory-store.js +118 -0
  75. package/dist/next-cache/redis-scripts.d.ts +3 -0
  76. package/dist/next-cache/redis-scripts.js +85 -0
  77. package/dist/next-cache/redis-store.d.ts +18 -0
  78. package/dist/next-cache/redis-store.js +56 -0
  79. package/dist/next-cache/runtime.d.ts +29 -0
  80. package/dist/next-cache/runtime.js +63 -0
  81. package/dist/next-cache/serialization.d.ts +39 -0
  82. package/dist/next-cache/serialization.js +333 -0
  83. package/dist/next-cache/store.d.ts +54 -0
  84. package/dist/next-cache/store.js +45 -0
  85. package/dist/next-cache/valkey-transport.d.ts +52 -0
  86. package/dist/next-cache/valkey-transport.js +189 -0
  87. package/dist/next-dev-control.d.ts +48 -0
  88. package/dist/next-dev-control.js +63 -0
  89. package/dist/next-dev-process.d.ts +17 -0
  90. package/dist/next-dev-process.js +110 -0
  91. package/dist/next-dev.d.ts +12 -0
  92. package/dist/next-dev.js +267 -0
  93. package/dist/next-image-config.d.ts +9 -0
  94. package/dist/next-image-config.js +101 -0
  95. package/dist/next-project.d.ts +22 -0
  96. package/dist/next-project.js +64 -0
  97. package/dist/next-public-fonts-local.d.ts +7 -0
  98. package/dist/next-public-fonts-local.js +64 -0
  99. package/dist/next-public-fonts.d.ts +13 -0
  100. package/dist/next-public-fonts.js +49 -0
  101. package/dist/next-source-hash.d.ts +14 -0
  102. package/dist/next-source-hash.js +18 -0
  103. package/dist/next-source.d.ts +35 -0
  104. package/dist/next-source.js +155 -0
  105. package/dist/next.d.ts +9 -0
  106. package/dist/next.js +5 -0
  107. package/dist/project.d.ts +3 -0
  108. package/dist/project.js +9 -1
  109. package/dist/runtime-contracts.d.ts +229 -0
  110. package/dist/runtime-contracts.js +224 -0
  111. package/dist/sdk.d.ts +420 -1
  112. package/dist/sdk.js +35 -0
  113. package/dist/server/broker-contract.d.ts +68 -0
  114. package/dist/server/broker-contract.js +33 -0
  115. package/dist/server/client.d.ts +67 -0
  116. package/dist/server/client.js +159 -0
  117. package/dist/server/logger.d.ts +26 -0
  118. package/dist/server/logger.js +24 -0
  119. package/dist/server/release-forms.d.ts +13 -0
  120. package/dist/server/release-forms.js +124 -0
  121. package/dist/server/request-context.d.ts +74 -0
  122. package/dist/server/request-context.js +103 -0
  123. package/dist/server/runtime-config.d.ts +53 -0
  124. package/dist/server/runtime-config.js +64 -0
  125. package/dist/server.d.ts +8 -0
  126. package/dist/server.js +4 -0
  127. package/dist/templates/nextjs/.artifactignore +14 -0
  128. package/dist/templates/nextjs/README.md +151 -0
  129. package/dist/templates/nextjs/app/about/page.tsx +26 -0
  130. package/dist/templates/nextjs/app/actions.ts +18 -0
  131. package/dist/templates/nextjs/app/api/health/route.ts +6 -0
  132. package/dist/templates/nextjs/app/components/counter.tsx +19 -0
  133. package/dist/templates/nextjs/app/components/greeting-form.tsx +38 -0
  134. package/dist/templates/nextjs/app/globals.css +4 -0
  135. package/dist/templates/nextjs/app/layout.tsx +27 -0
  136. package/dist/templates/nextjs/app/page.tsx +51 -0
  137. package/dist/templates/nextjs/app/providers.tsx +107 -0
  138. package/dist/templates/nextjs/artifact.bundle.yml +55 -0
  139. package/dist/templates/nextjs/next.config.mjs +27 -0
  140. package/dist/templates/nextjs/package.json +32 -0
  141. package/dist/templates/nextjs/pnpm-workspace.yaml +8 -0
  142. package/dist/templates/nextjs/postcss.config.mjs +5 -0
  143. package/dist/templates/nextjs/tsconfig.json +20 -0
  144. package/dist/templates/react-vite/artifact.bundle.yml +0 -1
  145. package/dist/templates/react-vite/package.json +1 -1
  146. package/dist/tunnel/broker.d.ts +75 -0
  147. package/dist/tunnel/broker.js +451 -0
  148. package/dist/tunnel/client.d.ts +22 -0
  149. package/dist/tunnel/client.js +177 -0
  150. package/dist/tunnel/index.d.ts +6 -0
  151. package/dist/tunnel/index.js +4 -0
  152. package/dist/tunnel/io.d.ts +33 -0
  153. package/dist/tunnel/io.js +108 -0
  154. package/dist/tunnel/peer.d.ts +25 -0
  155. package/dist/tunnel/peer.js +147 -0
  156. package/dist/tunnel/protocol.d.ts +69 -0
  157. package/dist/tunnel/protocol.js +196 -0
  158. package/dist/tunnel/redis-ownership.d.ts +38 -0
  159. package/dist/tunnel/redis-ownership.js +100 -0
  160. package/dist/tunnel/redis-socket.d.ts +13 -0
  161. package/dist/tunnel/redis-socket.js +48 -0
  162. package/dist/tunnel/redis-types.d.ts +70 -0
  163. package/dist/tunnel/redis-types.js +9 -0
  164. package/dist/tunnel/redis.d.ts +53 -0
  165. package/dist/tunnel/redis.js +391 -0
  166. package/dist/tunnel/transport.d.ts +17 -0
  167. package/dist/tunnel/transport.js +1 -0
  168. package/package.json +68 -4
  169. package/templates/nextjs/.artifactignore +14 -0
  170. package/templates/nextjs/README.md +151 -0
  171. package/templates/nextjs/app/about/page.tsx +26 -0
  172. package/templates/nextjs/app/actions.ts +18 -0
  173. package/templates/nextjs/app/api/health/route.ts +6 -0
  174. package/templates/nextjs/app/components/counter.tsx +19 -0
  175. package/templates/nextjs/app/components/greeting-form.tsx +38 -0
  176. package/templates/nextjs/app/globals.css +4 -0
  177. package/templates/nextjs/app/layout.tsx +27 -0
  178. package/templates/nextjs/app/page.tsx +51 -0
  179. package/templates/nextjs/app/providers.tsx +107 -0
  180. package/templates/nextjs/artifact.bundle.yml +55 -0
  181. package/templates/nextjs/next.config.mjs +27 -0
  182. package/templates/nextjs/package.json +32 -0
  183. package/templates/nextjs/pnpm-workspace.yaml +8 -0
  184. package/templates/nextjs/postcss.config.mjs +5 -0
  185. package/templates/nextjs/tsconfig.json +20 -0
  186. package/templates/react-vite/artifact.bundle.yml +0 -1
  187. package/templates/react-vite/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Artifact Studio SDK
2
+
3
+ `@sequenceholdings/artifact-studio` exposes the host-provided `seq` client. Runtime
4
+ requests use the current user's normal permissions.
5
+
6
+ Artifact Studio is a workflow-agnostic platform primitive. The host, SDK, and
7
+ deployer provide generic application capabilities; each deployed artifact owns
8
+ its product behavior. Primitive code must not branch on an artifact ID or import
9
+ an application's services. See [Platform primitive boundaries](../../../docs/platform/platform-primitives.md).
10
+
11
+ ## Grouping calls into a trace
12
+
13
+ The Artifact host supplies tracing context automatically for supported platform
14
+ requests. Use an explicit action scope to correlate several calls from one UI
15
+ action and supply a readable intent key:
16
+
17
+ ```ts
18
+ import { withTraceAction } from '@sequenceholdings/artifact-studio'
19
+
20
+ await withTraceAction(
21
+ { key: 'application.refresh' },
22
+ async ({ api, functions }) => {
23
+ await functions.invoke('my-function', { refresh: true })
24
+ await api.get('/api/my-application/summary')
25
+ },
26
+ )
27
+ ```
28
+
29
+ Use a stable operation label, never an identifier, customer value or payload. Each
30
+ scope gets its own correlation ID, so concurrent actions remain separate. The
31
+ helper scopes JSON `api.fetch/get/post/put/patch/delete` and `functions.invoke`;
32
+ streaming and file-transfer helpers retain their ordinary host tracing behavior.
33
+ Tracing does not grant permissions, change service-account behavior or guarantee
34
+ that every transport is instrumented. Traces availability depends on the deployed
35
+ platform version and your app/resource permissions.
package/VERSION-PIN.md CHANGED
@@ -4,12 +4,19 @@ A (re)built Artifact Studio app gets whatever `@sequenceholdings/atlas-ui` the
4
4
  **building CLI** carries — not a semver the artifact's own `package.json`
5
5
  declares.
6
6
 
7
- Artifact Studio 0.2.5 (Studio CLI 0.1.31) pins Atlas UI 3.1.2 exactly.
7
+ Artifact Studio 0.2.7 (Studio CLI 0.1.36) pins Atlas UI 3.3.0 exactly.
8
8
  Ordinary builds now use its canonical, mode-aware `tokens.css`. Rebuilding an
9
9
  existing artifact adopts this toolchain; previously uploaded immutable bundles
10
10
  keep their original CSS. Migrate retired numbered black/white utilities to
11
11
  semantic roles and verify a preview before activating a rebuilt artifact.
12
12
 
13
+ Artifact Studio 0.3.0 (Studio CLI 0.2.0) adds the opt-in Next.js runtime. The
14
+ static compiler continues to pin Atlas UI 3.3.0. Next.js applications own their
15
+ React 19 dependencies and use the `/next` client boundary that Atlas UI 3.4.0
16
+ introduces; they do not inherit the static compiler's aliases. The new packages must be published
17
+ before a fresh external Next.js scaffold can be installed. A local candidate
18
+ build is not evidence of registry availability.
19
+
13
20
  ## What this means
14
21
 
15
22
  `shared/services/artifact-studio/src/build.ts` force-aliases platform peers via
@@ -53,8 +60,12 @@ never claims `no-op` for a deploy that would actually rebuild.
53
60
 
54
61
  `tokens.css` is the canonical stylesheet and includes semantic roles plus the
55
62
  Tailwind utility bridge. The legacy `tokens.v2.css` and `theme.v2.css` paths are
56
- temporary forwarding aliases; the compiler normalizes their source imports to one
57
- canonical layer and reports a migration warning. An explicit
63
+ temporary forwarding aliases in current packages; the compiler normalizes their
64
+ source imports to one canonical layer and reports a migration warning only after
65
+ checking that both selected files are forwarding aliases. Older packages carry
66
+ independent styles in those files, so their imports and provenance entries are
67
+ preserved. This prevents CRM spacing and corner utilities from disappearing when
68
+ rebuilding with a split-sheet package. An explicit
58
69
  `seq-studio artifact dev --link <atlas-ui-package-dir>` preview additionally
59
70
  reports retired numbered black/white opacity utilities and uncertain dynamic
60
71
  class construction. Legacy stylesheet aliases normalize to canonical tokens;
package/dist/api.d.ts CHANGED
@@ -2,13 +2,23 @@ export interface ApiClientOptions {
2
2
  baseUrl: string;
3
3
  token: string;
4
4
  }
5
+ export declare class ArtifactApiError extends Error {
6
+ readonly status: number;
7
+ constructor(message: string, status: number);
8
+ }
5
9
  export declare function getJson<T>({ baseUrl, token, path }: ApiClientOptions & {
6
10
  path: string;
7
11
  }): Promise<T>;
8
12
  export declare function getJsonOr404<T>({ baseUrl, token, path }: ApiClientOptions & {
9
13
  path: string;
10
14
  }): Promise<T | null>;
11
- export declare function postJson<T>({ baseUrl, token, path, body, }: ApiClientOptions & {
15
+ export declare function postJson<T>({ baseUrl, token, path, body, retry503, signal, }: ApiClientOptions & {
12
16
  path: string;
13
17
  body?: unknown;
18
+ retry503?: boolean;
19
+ signal?: AbortSignal;
14
20
  }): Promise<T>;
21
+ export declare function deleteJson({ baseUrl, token, path, signal }: ApiClientOptions & {
22
+ path: string;
23
+ signal?: AbortSignal;
24
+ }): Promise<void>;
package/dist/api.js CHANGED
@@ -1,4 +1,13 @@
1
+ import { setTimeout as delay } from 'node:timers/promises';
1
2
  import { authenticatedRequestUrl } from './deployment-validation.js';
3
+ export class ArtifactApiError extends Error {
4
+ status;
5
+ constructor(message, status) {
6
+ super(message);
7
+ this.status = status;
8
+ this.name = 'ArtifactApiError';
9
+ }
10
+ }
2
11
  const MAX_503_RETRIES = 5;
3
12
  const DEFAULT_RETRY_AFTER_SECONDS = 2;
4
13
  /**
@@ -36,19 +45,20 @@ function extraHeaders() {
36
45
  return {};
37
46
  }
38
47
  }
39
- async function fetchWith503Retry(input, init) {
48
+ async function fetchWith503Retry(input, init, maxRetries = MAX_503_RETRIES) {
40
49
  let attempt = 0;
41
50
  while (true) {
42
51
  const response = await fetch(input, init);
43
- if (response.status !== 503 || attempt >= MAX_503_RETRIES)
52
+ if (response.status !== 503 || attempt >= maxRetries)
44
53
  return response;
45
54
  const retryAfter = Number(response.headers.get('Retry-After')) || DEFAULT_RETRY_AFTER_SECONDS;
46
55
  attempt += 1;
47
56
  console.warn(`[seq-studio] backend warming up (503); retrying in ${retryAfter}s (attempt ${attempt}/${MAX_503_RETRIES})`);
48
- await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
57
+ // An aborted caller (e.g. artifact dev shutting down) must not wait out a Retry-After.
58
+ await delay(retryAfter * 1000, undefined, init.signal ? { signal: init.signal } : undefined);
49
59
  }
50
60
  }
51
- async function authenticatedFetch({ baseUrl, init = {}, path, token, }) {
61
+ async function authenticatedFetch({ baseUrl, init = {}, path, token, retry503 = true, }) {
52
62
  const url = authenticatedRequestUrl({ baseUrl, path });
53
63
  return fetchWith503Retry(url, {
54
64
  ...init,
@@ -58,12 +68,12 @@ async function authenticatedFetch({ baseUrl, init = {}, path, token, }) {
58
68
  ...init.headers,
59
69
  Authorization: `Bearer ${token}`,
60
70
  },
61
- });
71
+ }, retry503 ? MAX_503_RETRIES : 0);
62
72
  }
63
73
  export async function getJson({ baseUrl, token, path }) {
64
74
  const response = await authenticatedFetch({ baseUrl, token, path });
65
75
  if (!response.ok)
66
- throw new Error(await responseError('GET', path, response));
76
+ throw new ArtifactApiError(await responseError('GET', path, response), response.status);
67
77
  return response.json();
68
78
  }
69
79
  export async function getJsonOr404({ baseUrl, token, path }) {
@@ -71,24 +81,31 @@ export async function getJsonOr404({ baseUrl, token, path }) {
71
81
  if (response.status === 404)
72
82
  return null;
73
83
  if (!response.ok)
74
- throw new Error(await responseError('GET', path, response));
84
+ throw new ArtifactApiError(await responseError('GET', path, response), response.status);
75
85
  return response.json();
76
86
  }
77
- export async function postJson({ baseUrl, token, path, body, }) {
87
+ export async function postJson({ baseUrl, token, path, body, retry503 = true, signal, }) {
78
88
  const response = await authenticatedFetch({
79
89
  baseUrl,
80
90
  token,
81
91
  path,
92
+ retry503,
82
93
  init: {
83
94
  method: 'POST',
84
95
  headers: { 'Content-Type': 'application/json' },
85
96
  body: body === undefined ? undefined : JSON.stringify(body),
97
+ ...(signal ? { signal } : {}),
86
98
  },
87
99
  });
88
100
  if (!response.ok)
89
- throw new Error(await responseError('POST', path, response));
101
+ throw new ArtifactApiError(await responseError('POST', path, response), response.status);
90
102
  return response.json();
91
103
  }
104
+ export async function deleteJson({ baseUrl, token, path, signal }) {
105
+ const response = await authenticatedFetch({ baseUrl, token, path, init: { method: 'DELETE', ...(signal ? { signal } : {}) } });
106
+ if (!response.ok)
107
+ throw new ArtifactApiError(await responseError('DELETE', path, response), response.status);
108
+ }
92
109
  /**
93
110
  * Build an actionable error message from a failed response: which request
94
111
  * failed, with what status, and what the server said. A deploy runs several
@@ -1,11 +1,15 @@
1
1
  import type { Plugin } from 'vite';
2
2
  export interface AtlasUiResolvedTokenSelection {
3
- specifier: '@sequenceholdings/atlas-ui/tokens.css';
3
+ specifier: string;
4
4
  injectedBy: string | null;
5
5
  }
6
+ /** Only collapse aliases when the selected package makes them forwarding sheets.
7
+ * Older releases define independent semantic tokens and the Tailwind bridge there.
8
+ */
9
+ export declare function hasUnifiedAtlasUiTokens(atlasUiDir: string): boolean;
6
10
  /**
7
- * Every supported source shape becomes one canonical import before Tailwind
8
- * expands it. The aliases remain package-compatible, but are no longer allowed
11
+ * For packages with forwarding aliases, collapse imports before Tailwind
12
+ * expands them. The aliases remain package-compatible, but are no longer allowed
9
13
  * to create duplicate token layers in an Artifact Studio bundle (DES-437).
10
14
  */
11
15
  export declare function normalizeAtlasUiTokenImports(code: string): {
@@ -13,10 +17,10 @@ export declare function normalizeAtlasUiTokenImports(code: string): {
13
17
  deprecatedImports: string[];
14
18
  };
15
19
  /**
16
- * Evidence mirrors the CSS transform: aliases are normalized away, so the only
17
- * selected sheet is the canonical token entry point.
20
+ * Evidence mirrors the selected package: split sheets remain separate entries;
21
+ * forwarding aliases are normalized to the canonical entry point.
18
22
  */
19
- export declare function collectAtlasUiResolvedTokenSelections({ cssModules, }: {
23
+ export declare function collectAtlasUiResolvedTokenSelections({ cssModules, atlasUiDir, }: {
20
24
  cssModules: readonly {
21
25
  id: string;
22
26
  code: string;
@@ -25,7 +29,7 @@ export declare function collectAtlasUiResolvedTokenSelections({ cssModules, }: {
25
29
  atlasUiDist: string;
26
30
  formRendererDist: string | null;
27
31
  }): AtlasUiResolvedTokenSelection[];
28
- export declare function atlasUiCssResolverPlugin({ atlasUiDir: _atlasUiDir, atlasUiDist, formRendererDist, onTransform, }: {
32
+ export declare function atlasUiCssResolverPlugin({ atlasUiDir, atlasUiDist, formRendererDist, onTransform, }: {
29
33
  atlasUiDir: string;
30
34
  atlasUiDist: string;
31
35
  formRendererDist: string | null;
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
3
  import { dirname, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
@@ -19,14 +19,26 @@ function resolveTwAnimateCssPath() {
19
19
  }
20
20
  const CANONICAL_TOKEN_IMPORT = '@import "@sequenceholdings/atlas-ui/tokens.css";';
21
21
  const ATLAS_UI_TOKEN_IMPORT = /@import\s+(?:url\(\s*)?(?:["'][^"']*?@sequenceholdings\/atlas-ui\/|[^"'()\s;]*@sequenceholdings\/atlas-ui\/)(tokens\.css|tokens\.v2\.css|theme\.v2\.css)(?:["'])?\s*\)?[^;\n]*;/gi;
22
+ /** Only collapse aliases when the selected package makes them forwarding sheets.
23
+ * Older releases define independent semantic tokens and the Tailwind bridge there.
24
+ */
25
+ export function hasUnifiedAtlasUiTokens(atlasUiDir) {
26
+ return ['tokens.v2.css', 'theme.v2.css'].every((sheet) => {
27
+ const path = resolve(atlasUiDir, sheet);
28
+ if (!existsSync(path))
29
+ return false;
30
+ const content = readFileSync(path, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '').trim();
31
+ return /^@import\s+["']@sequenceholdings\/atlas-ui\/tokens\.css["'];$/.test(content);
32
+ });
33
+ }
22
34
  function atlasUiTokenImportSheets(code) {
23
35
  return [...code.matchAll(ATLAS_UI_TOKEN_IMPORT)]
24
36
  .map((match) => match[1]?.toLowerCase())
25
37
  .filter((sheet) => sheet !== undefined);
26
38
  }
27
39
  /**
28
- * Every supported source shape becomes one canonical import before Tailwind
29
- * expands it. The aliases remain package-compatible, but are no longer allowed
40
+ * For packages with forwarding aliases, collapse imports before Tailwind
41
+ * expands them. The aliases remain package-compatible, but are no longer allowed
30
42
  * to create duplicate token layers in an Artifact Studio bundle (DES-437).
31
43
  */
32
44
  export function normalizeAtlasUiTokenImports(code) {
@@ -43,16 +55,23 @@ export function normalizeAtlasUiTokenImports(code) {
43
55
  };
44
56
  }
45
57
  /**
46
- * Evidence mirrors the CSS transform: aliases are normalized away, so the only
47
- * selected sheet is the canonical token entry point.
58
+ * Evidence mirrors the selected package: split sheets remain separate entries;
59
+ * forwarding aliases are normalized to the canonical entry point.
48
60
  */
49
- export function collectAtlasUiResolvedTokenSelections({ cssModules, }) {
61
+ export function collectAtlasUiResolvedTokenSelections({ cssModules, atlasUiDir, }) {
50
62
  for (const { code } of cssModules) {
51
63
  if (!code.includes('@import "tailwindcss"'))
52
64
  continue;
65
+ const sheets = atlasUiTokenImportSheets(code);
66
+ if (!hasUnifiedAtlasUiTokens(atlasUiDir)) {
67
+ return [...new Set(['tokens.css', ...sheets])].map((sheet) => ({
68
+ specifier: `@sequenceholdings/atlas-ui/${sheet}`,
69
+ injectedBy: sheets.includes(sheet) ? null : 'atlas-ui-css-resolver',
70
+ }));
71
+ }
53
72
  return [{
54
73
  specifier: '@sequenceholdings/atlas-ui/tokens.css',
55
- injectedBy: atlasUiTokenImportSheets(code).includes('tokens.css') ? null : 'atlas-ui-css-resolver',
74
+ injectedBy: sheets.includes('tokens.css') ? null : 'atlas-ui-css-resolver',
56
75
  }];
57
76
  }
58
77
  return [];
@@ -70,7 +89,8 @@ function insertAfterImports(code, lines) {
70
89
  const end = lastImport.index + lastImport[0].length;
71
90
  return `${code.slice(0, end)}${block}${code.slice(end)}`;
72
91
  }
73
- export function atlasUiCssResolverPlugin({ atlasUiDir: _atlasUiDir, atlasUiDist, formRendererDist, onTransform, }) {
92
+ export function atlasUiCssResolverPlugin({ atlasUiDir, atlasUiDist, formRendererDist, onTransform, }) {
93
+ const unifiedTokens = hasUnifiedAtlasUiTokens(atlasUiDir);
74
94
  return {
75
95
  name: 'atlas-ui-css-resolver',
76
96
  enforce: 'pre',
@@ -88,8 +108,16 @@ export function atlasUiCssResolverPlugin({ atlasUiDir: _atlasUiDir, atlasUiDist,
88
108
  if (formRendererDist) {
89
109
  sources.push(`@source ${JSON.stringify(formRendererDist)};`);
90
110
  }
91
- const tokenImports = normalizeAtlasUiTokenImports(result);
92
- result = tokenImports.code;
111
+ if (unifiedTokens) {
112
+ result = normalizeAtlasUiTokenImports(result).code;
113
+ }
114
+ else if (!atlasUiTokenImportSheets(result).includes('tokens.css')) {
115
+ const firstTokenImport = result.match(ATLAS_UI_TOKEN_IMPORT)?.[0];
116
+ // The old base must precede the semantic overrides in split packages.
117
+ result = firstTokenImport
118
+ ? result.replace(firstTokenImport, `${CANONICAL_TOKEN_IMPORT}\n${firstTokenImport}`)
119
+ : insertAfterImports(result, [CANONICAL_TOKEN_IMPORT]);
120
+ }
93
121
  result = insertAfterImports(result, sources);
94
122
  }
95
123
  if (result.includes('@import "tw-animate-css"')) {
package/dist/build.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type ObservedBuildEvidence } from './build-provenance.js';
2
2
  import { type ArtifactStudioSourceFile } from './project.js';
3
- import type { ArtifactStudioManifest } from './manifest.js';
3
+ import { type ArtifactStudioStaticManifest } from './manifest.js';
4
4
  import { type ArtifactStudioPeerVersions } from './peer-versions.js';
5
5
  /**
6
6
  * Released Atlas UI 2.0.1 exports its canonical sheet from dist, while the
@@ -17,7 +17,7 @@ export interface ArtifactStudioRuntimeChunk {
17
17
  }
18
18
  export type ArtifactStudioBundleFormat = 'esm';
19
19
  export interface ArtifactStudioBuildResult {
20
- manifest: ArtifactStudioManifest;
20
+ manifest: ArtifactStudioStaticManifest;
21
21
  files: ArtifactStudioSourceFile[];
22
22
  /** Entry module (ESM). Lazy routes land in `chunks`. */
23
23
  bundle: string;
package/dist/build.js CHANGED
@@ -3,13 +3,14 @@ import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { createRequire } from 'node:module';
4
4
  import { dirname, relative, resolve } from 'node:path';
5
5
  import { build as viteBuild } from 'vite';
6
- import { atlasUiCssResolverPlugin, collectAtlasUiResolvedTokenSelections } from './atlas-ui-css-plugin.js';
6
+ import { atlasUiCssResolverPlugin, collectAtlasUiResolvedTokenSelections, hasUnifiedAtlasUiTokens } from './atlas-ui-css-plugin.js';
7
7
  import { validateAtlasUiTokenStylesheetContract } from './atlas-ui-package-contract.js';
8
8
  import { createObservedBuildEvidence } from './build-provenance.js';
9
9
  import { collectResolvedStylesheets } from './resolved-stylesheets.js';
10
10
  import { sha256Hex } from './hash.js';
11
11
  import { isArtifactIgnoredPath } from './artifact-ignore.js';
12
12
  import { readArtifactStudioSource } from './project.js';
13
+ import { isNextArtifactManifest } from './manifest.js';
13
14
  import { normalizeArtifactPath } from './paths.js';
14
15
  import { resolveArtifactStudioPeerVersions, } from './peer-versions.js';
15
16
  import { ARTIFACT_RUNTIME_CHUNK_DIR, assertSafeRuntimeChunkFileName } from './runtime-chunks.js';
@@ -31,6 +32,7 @@ const reactRouterDomDir = dirname(cliRequire.resolve('react-router-dom/package.j
31
32
  const sonnerDir = dirname(cliRequire.resolve('sonner'));
32
33
  const atlasUiDir = dirname(cliRequire.resolve('@sequenceholdings/atlas-ui/package.json'));
33
34
  const atlasUiDist = resolve(atlasUiDir, 'dist');
35
+ const artifactSdkEntry = cliRequire.resolve('@sequenceholdings/artifact-studio');
34
36
  /**
35
37
  * Released Atlas UI 2.0.1 exports its canonical sheet from dist, while the
36
38
  * candidate layout puts the generated entry at package root so it can be read
@@ -75,6 +77,7 @@ function createPeerResolveAlias({ atlasUiPackageDir = atlasUiDir } = {}) {
75
77
  '@tanstack/react-query': reactQueryDir,
76
78
  'react-router-dom': reactRouterDomDir,
77
79
  sonner: sonnerDir,
80
+ '@sequenceholdings/storage': cliRequire.resolve('@sequenceholdings/storage'),
78
81
  // Candidate Atlas UI exposes canonical tokens at the package root; released
79
82
  // 2.0.1 keeps them in dist. Preserve explicit alias resolution so legacy
80
83
  // source reaches the normalizer instead of falling through to the bare alias.
@@ -101,8 +104,13 @@ export async function buildArtifactStudioProject(rootDir, { candidateTokenCompat
101
104
  const selectedAtlasUiDist = resolve(atlasUiPackageDir ?? atlasUiDir, 'dist');
102
105
  const selectedAtlasUiTokens = resolveAtlasUiTokensPath(selectedAtlasUiDir);
103
106
  const source = await readArtifactStudioSource(rootDir);
107
+ if (isNextArtifactManifest(source.manifest)) {
108
+ throw new Error('Next.js applications are built by Atlas. Run seq-studio artifact build --env <env>.');
109
+ }
104
110
  const diagnostics = [
105
- ...collectDeprecatedTokenImportDiagnostics({ files: source.files }),
111
+ ...(hasUnifiedAtlasUiTokens(selectedAtlasUiDir)
112
+ ? collectDeprecatedTokenImportDiagnostics({ files: source.files })
113
+ : []),
106
114
  ...(candidateTokenCompatibility
107
115
  ? collectCandidateTokenCompatibilityDiagnostics({ files: source.files })
108
116
  : []),
@@ -116,7 +124,7 @@ export async function buildArtifactStudioProject(rootDir, { candidateTokenCompat
116
124
  plugins: [
117
125
  rejectOutsideSourcePlugin({
118
126
  root,
119
- trustedExternalRoots: Object.values(peerResolveAlias).map((target) => dirname(target)),
127
+ trustedExternalRoots: [...Object.values(peerResolveAlias).map((target) => dirname(target)), dirname(artifactSdkEntry)],
120
128
  }),
121
129
  rejectIgnoredSourcePlugin(root, source.ignorePatterns),
122
130
  artifactSdkVirtualModule(),
@@ -267,8 +275,8 @@ function artifactSdkVirtualModule() {
267
275
  // host-injected `window.seq`, so a tree that happens to be `pnpm install`ed
268
276
  // must produce the same bundle as a bare tree (e.g. one materialized from a
269
277
  // git repo) — otherwise the same source yields different bytes depending on
270
- // whether node_modules exists. The package's sole runtime export is `seq`
271
- // (everything else is type-only), so this stub is a complete substitute.
278
+ // whether node_modules exists. Use the CLI's SDK entry so runtime helpers
279
+ // stay in sync with the types instead of maintaining a partial export stub.
272
280
  enforce: 'pre',
273
281
  resolveId(id) {
274
282
  return virtualIds.has(id) ? resolved : undefined;
@@ -276,7 +284,7 @@ function artifactSdkVirtualModule() {
276
284
  load(id) {
277
285
  if (id !== resolved)
278
286
  return undefined;
279
- return 'export const seq = window.seq; export default window.seq;';
287
+ return `export * from ${JSON.stringify(artifactSdkEntry)}; export { default } from ${JSON.stringify(artifactSdkEntry)};`;
280
288
  },
281
289
  };
282
290
  }
package/dist/cli.d.ts CHANGED
@@ -5,7 +5,7 @@ interface RemoteProject {
5
5
  id: string;
6
6
  slug: string;
7
7
  title: string;
8
- visibility?: string;
8
+ projectType?: string;
9
9
  activeDeployment?: {
10
10
  version: string;
11
11
  sourceHash: string;