@sequenceholdings/artifact-studio 0.2.6 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/VERSION-PIN.md +12 -1
  2. package/dist/api.d.ts +11 -1
  3. package/dist/api.js +26 -9
  4. package/dist/build.d.ts +2 -2
  5. package/dist/build.js +4 -0
  6. package/dist/cli.d.ts +1 -0
  7. package/dist/cli.js +134 -13
  8. package/dist/dev-link.d.ts +1 -1
  9. package/dist/dev-link.js +2 -1
  10. package/dist/gateway/admission.d.ts +56 -0
  11. package/dist/gateway/admission.js +134 -0
  12. package/dist/gateway/authorization-cache.d.ts +52 -0
  13. package/dist/gateway/authorization-cache.js +111 -0
  14. package/dist/gateway/control-admission.d.ts +48 -0
  15. package/dist/gateway/control-admission.js +127 -0
  16. package/dist/gateway/control.d.ts +94 -0
  17. package/dist/gateway/control.js +116 -0
  18. package/dist/gateway/hosted-proxy.d.ts +36 -0
  19. package/dist/gateway/hosted-proxy.js +344 -0
  20. package/dist/gateway/release-admission.d.ts +23 -0
  21. package/dist/gateway/release-admission.js +259 -0
  22. package/dist/gateway/server.d.ts +38 -0
  23. package/dist/gateway/server.js +382 -0
  24. package/dist/gateway/session.d.ts +72 -0
  25. package/dist/gateway/session.js +144 -0
  26. package/dist/gateway/usage.d.ts +70 -0
  27. package/dist/gateway/usage.js +116 -0
  28. package/dist/gateway-main.d.ts +1 -0
  29. package/dist/gateway-main.js +114 -0
  30. package/dist/git-clone.d.ts +23 -1
  31. package/dist/git-clone.js +32 -15
  32. package/dist/manifest-next.d.ts +217 -0
  33. package/dist/manifest-next.js +132 -0
  34. package/dist/manifest-static.d.ts +76 -0
  35. package/dist/manifest-static.js +124 -0
  36. package/dist/manifest.d.ts +118 -13
  37. package/dist/manifest.js +12 -119
  38. package/dist/next/bridge.d.ts +47 -0
  39. package/dist/next/bridge.js +236 -0
  40. package/dist/next/browser-logs.d.ts +7 -0
  41. package/dist/next/browser-logs.js +51 -0
  42. package/dist/next/browser.d.ts +6 -0
  43. package/dist/next/browser.js +57 -0
  44. package/dist/next/protocol.d.ts +73 -0
  45. package/dist/next/protocol.js +56 -0
  46. package/dist/next/release.d.ts +15 -0
  47. package/dist/next/release.js +46 -0
  48. package/dist/next/requests.d.ts +15 -0
  49. package/dist/next/requests.js +59 -0
  50. package/dist/next/routes.d.ts +4 -0
  51. package/dist/next/routes.js +21 -0
  52. package/dist/next/streams.d.ts +16 -0
  53. package/dist/next/streams.js +132 -0
  54. package/dist/next/theme.d.ts +10 -0
  55. package/dist/next/theme.js +45 -0
  56. package/dist/next/transport.d.ts +15 -0
  57. package/dist/next/transport.js +13 -0
  58. package/dist/next-build.d.ts +29 -0
  59. package/dist/next-build.js +129 -0
  60. package/dist/next-cache/adapter-runtime.d.ts +51 -0
  61. package/dist/next-cache/adapter-runtime.js +73 -0
  62. package/dist/next-cache/component-handler.d.ts +3 -0
  63. package/dist/next-cache/component-handler.js +10 -0
  64. package/dist/next-cache/components.d.ts +20 -0
  65. package/dist/next-cache/components.js +113 -0
  66. package/dist/next-cache/config.d.ts +9 -0
  67. package/dist/next-cache/config.js +105 -0
  68. package/dist/next-cache/incremental-handler.d.ts +18 -0
  69. package/dist/next-cache/incremental-handler.js +17 -0
  70. package/dist/next-cache/incremental.d.ts +27 -0
  71. package/dist/next-cache/incremental.js +99 -0
  72. package/dist/next-cache/index.d.ts +18 -0
  73. package/dist/next-cache/index.js +16 -0
  74. package/dist/next-cache/memory-store.d.ts +27 -0
  75. package/dist/next-cache/memory-store.js +118 -0
  76. package/dist/next-cache/redis-scripts.d.ts +3 -0
  77. package/dist/next-cache/redis-scripts.js +85 -0
  78. package/dist/next-cache/redis-store.d.ts +18 -0
  79. package/dist/next-cache/redis-store.js +56 -0
  80. package/dist/next-cache/runtime.d.ts +29 -0
  81. package/dist/next-cache/runtime.js +63 -0
  82. package/dist/next-cache/serialization.d.ts +39 -0
  83. package/dist/next-cache/serialization.js +333 -0
  84. package/dist/next-cache/store.d.ts +54 -0
  85. package/dist/next-cache/store.js +45 -0
  86. package/dist/next-cache/valkey-transport.d.ts +52 -0
  87. package/dist/next-cache/valkey-transport.js +189 -0
  88. package/dist/next-dev-control.d.ts +48 -0
  89. package/dist/next-dev-control.js +63 -0
  90. package/dist/next-dev-process.d.ts +17 -0
  91. package/dist/next-dev-process.js +110 -0
  92. package/dist/next-dev.d.ts +12 -0
  93. package/dist/next-dev.js +267 -0
  94. package/dist/next-image-config.d.ts +9 -0
  95. package/dist/next-image-config.js +101 -0
  96. package/dist/next-project.d.ts +22 -0
  97. package/dist/next-project.js +64 -0
  98. package/dist/next-public-fonts-local.d.ts +7 -0
  99. package/dist/next-public-fonts-local.js +64 -0
  100. package/dist/next-public-fonts.d.ts +13 -0
  101. package/dist/next-public-fonts.js +49 -0
  102. package/dist/next-source-hash.d.ts +14 -0
  103. package/dist/next-source-hash.js +18 -0
  104. package/dist/next-source.d.ts +35 -0
  105. package/dist/next-source.js +155 -0
  106. package/dist/next.d.ts +9 -0
  107. package/dist/next.js +5 -0
  108. package/dist/project.d.ts +3 -0
  109. package/dist/project.js +9 -1
  110. package/dist/runtime-contracts.d.ts +229 -0
  111. package/dist/runtime-contracts.js +224 -0
  112. package/dist/sdk.d.ts +2 -2
  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 +81 -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 +75 -0
  122. package/dist/server/request-context.js +107 -0
  123. package/dist/server/runtime-config.d.ts +54 -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 +157 -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/gitignore +9 -0
  140. package/dist/templates/nextjs/next.config.mjs +27 -0
  141. package/dist/templates/nextjs/package.json +32 -0
  142. package/dist/templates/nextjs/pnpm-workspace.yaml +22 -0
  143. package/dist/templates/nextjs/postcss.config.mjs +5 -0
  144. package/dist/templates/nextjs/tsconfig.json +20 -0
  145. package/dist/templates/react-vite/package.json +1 -1
  146. package/dist/trusted-install.js +62 -2
  147. package/dist/tunnel/broker.d.ts +75 -0
  148. package/dist/tunnel/broker.js +463 -0
  149. package/dist/tunnel/client.d.ts +22 -0
  150. package/dist/tunnel/client.js +177 -0
  151. package/dist/tunnel/index.d.ts +6 -0
  152. package/dist/tunnel/index.js +4 -0
  153. package/dist/tunnel/io.d.ts +33 -0
  154. package/dist/tunnel/io.js +108 -0
  155. package/dist/tunnel/peer.d.ts +25 -0
  156. package/dist/tunnel/peer.js +147 -0
  157. package/dist/tunnel/protocol.d.ts +78 -0
  158. package/dist/tunnel/protocol.js +210 -0
  159. package/dist/tunnel/redis-auth.d.ts +37 -0
  160. package/dist/tunnel/redis-auth.js +92 -0
  161. package/dist/tunnel/redis-ownership.d.ts +38 -0
  162. package/dist/tunnel/redis-ownership.js +100 -0
  163. package/dist/tunnel/redis-socket.d.ts +13 -0
  164. package/dist/tunnel/redis-socket.js +48 -0
  165. package/dist/tunnel/redis-types.d.ts +75 -0
  166. package/dist/tunnel/redis-types.js +9 -0
  167. package/dist/tunnel/redis.d.ts +56 -0
  168. package/dist/tunnel/redis.js +404 -0
  169. package/dist/tunnel/transport.d.ts +17 -0
  170. package/dist/tunnel/transport.js +1 -0
  171. package/package.json +67 -4
  172. package/templates/nextjs/.artifactignore +14 -0
  173. package/templates/nextjs/README.md +157 -0
  174. package/templates/nextjs/app/about/page.tsx +26 -0
  175. package/templates/nextjs/app/actions.ts +18 -0
  176. package/templates/nextjs/app/api/health/route.ts +6 -0
  177. package/templates/nextjs/app/components/counter.tsx +19 -0
  178. package/templates/nextjs/app/components/greeting-form.tsx +38 -0
  179. package/templates/nextjs/app/globals.css +4 -0
  180. package/templates/nextjs/app/layout.tsx +27 -0
  181. package/templates/nextjs/app/page.tsx +51 -0
  182. package/templates/nextjs/app/providers.tsx +107 -0
  183. package/templates/nextjs/artifact.bundle.yml +55 -0
  184. package/templates/nextjs/gitignore +9 -0
  185. package/templates/nextjs/next.config.mjs +27 -0
  186. package/templates/nextjs/package.json +32 -0
  187. package/templates/nextjs/pnpm-workspace.yaml +22 -0
  188. package/templates/nextjs/postcss.config.mjs +5 -0
  189. package/templates/nextjs/tsconfig.json +20 -0
  190. package/templates/react-vite/package.json +1 -1
@@ -0,0 +1,157 @@
1
+ # Next.js on Artifact Studio
2
+
3
+ This app uses Next.js App Router, React 19 and Node 24. Its source and development
4
+ server live on your machine; Atlas manages access, previews and deployment. You
5
+ do not need GCP credentials or a cloud devbox.
6
+
7
+ ## Get started
8
+
9
+ Install Node 24, pnpm and a released `seq-studio` version with Next.js support.
10
+ Your Atlas environment must have the Next.js runtime enabled.
11
+
12
+ From this directory:
13
+
14
+ ```sh
15
+ pnpm install
16
+ seq-studio envs list
17
+ seq-studio login --env <your-environment>
18
+ seq-studio artifact link --env <your-environment>
19
+ seq-studio artifact dev --env <your-environment>
20
+ ```
21
+
22
+ Use an environment shown by `envs list`; for an OpCo, log in to that environment's
23
+ realm. The CLI opens an owner-only preview in Atlas and connects it to Next.js
24
+ over an authenticated outbound tunnel. Keep the process running while you edit.
25
+ Use Ctrl+C to stop it. When your machine is offline, the preview is offline too.
26
+
27
+ Local development uses Webpack with native Fast Refresh. This is the supported
28
+ bundler for the pinned Next.js release; it preserves client navigation during
29
+ updates through the Atlas preview. Dependency changes restart the
30
+ local server; linked package edits rebuild and restart it. Changes to
31
+ `artifact.bundle.yml` end the current session—restart `artifact dev` to authorize
32
+ the new configuration and permissions.
33
+
34
+ Commit the generated `pnpm-lock.yaml` with the app source. The workspace policy
35
+ keeps the seven-day dependency age gate and explicit install-script decisions.
36
+ Do not commit registry credentials or a project `.npmrc`.
37
+
38
+ For a standalone UI check without Atlas, run `pnpm dev` and open the loopback URL.
39
+ Atlas SDK calls require an authorized Atlas development session. The CLI sets
40
+ `ARTIFACT_STUDIO_DEV_ORIGIN` for the exact preview host; do not replace it with a
41
+ wildcard. Native Next.js routing is used throughout—no hash router or `basePath`.
42
+
43
+ ## What to edit
44
+
45
+ | File | Purpose |
46
+ | --- | --- |
47
+ | `app/page.tsx` | Request-time Server Component and client interaction examples |
48
+ | `app/actions.ts` | Validated server action; this example stores no data |
49
+ | `app/api/health/route.ts` | App-owned route handler |
50
+ | `app/providers.tsx` | Client boundary for the Atlas bridge, UI portals and React Query |
51
+ | `app/about/page.tsx` | Nested route for exercising Atlas and Next navigation |
52
+ | `artifact.bundle.yml` | Browser/server permissions and hosted runtime requirements |
53
+
54
+ `app/layout.tsx` verifies the gateway's request context and passes only safe UI
55
+ bootstrap data into the browser. Import Atlas UI components through
56
+ `@sequenceholdings/atlas-ui/next`, which preserves their React client boundary.
57
+ Keep `@sequenceholdings/artifact-studio/server` imports in
58
+ Server Components, server actions or route handlers. Framework route/layout and
59
+ configuration files use the default exports required by Next.js; other modules
60
+ use named exports.
61
+
62
+ Try incrementing the counter, then changing its label in
63
+ `app/components/counter.tsx`. Compatible edits preserve its value through Fast
64
+ Refresh. Submit the greeting form to exercise a server action; server validation
65
+ still applies when browser validation is bypassed.
66
+
67
+ ## Data and secrets
68
+
69
+ Browser permissions and server permissions are separate in the manifest. Add
70
+ only the capabilities the application needs, then configure authorized resource
71
+ bindings in Atlas. Local development uses explicit nonproduction resources and
72
+ never falls back to production when a binding is missing.
73
+
74
+ ORM access is declared per table and per mutation: list `<namespace>/<table>`
75
+ under `data.read` for every table a query reads (queries that follow
76
+ platform-user relations also read `<namespace>/platformUsers`). Under
77
+ `data.write`, use `<namespace>/ops/<Operation>` for each persisted mutation the
78
+ app runs, or `<namespace>/<table>` for table-level coverage.
79
+
80
+ Managed secrets stay in hosted runtimes. For local integration tests, use your
81
+ own test credentials, mocks or an existing governed function. Use a hosted
82
+ preview for application code that needs a managed secret. Never put secrets in
83
+ `build.public_env`, `NEXT_PUBLIC_*`, client components or committed files.
84
+
85
+ The local process is ordinary code running as your operating-system user.
86
+ Atlas governs access to platform resources; it does not sandbox your laptop's
87
+ filesystem or all outbound network connections.
88
+
89
+ ## Build and deploy
90
+
91
+ ```sh
92
+ pnpm type-check
93
+ pnpm build
94
+ seq-studio artifact plan --env <your-environment>
95
+ seq-studio artifact deploy --repo <namespace>/<repository> --ref main --env <your-environment>
96
+ ```
97
+
98
+ Push the reviewed application source and lockfile to its Git Service repository
99
+ before deploying. The local build is a validation step. Atlas performs the official isolated build
100
+ from recorded source and a lockfile, then operates the hosted Next.js server.
101
+ Deployments do not depend on your laptop staying online. Reviewers use hosted
102
+ previews rather than your owner-only local session.
103
+
104
+ For official releases to deployed environments, use a clean reviewed `main`
105
+ revision under the existing Artifact deployment policy. Inspect build/deployment
106
+ status, permissions and runtime diagnostics in Artifact Studio. Failed runtime
107
+ checks do not replace the previous healthy release.
108
+
109
+ The default scaffold is dynamic and declares no distributed cache. Enable managed
110
+ cache capacity in Atlas before adopting framework features that require shared
111
+ cross-replica caching; local Fast Refresh is not a test of distributed cache
112
+ behavior. Do not add a production cache endpoint or managed credentials to local
113
+ environment files.
114
+
115
+ ## Toolchain updates
116
+
117
+ This scaffold pins Next.js `16.3.4`, React/React DOM `19.2.6` and pnpm `10.28.2`,
118
+ with Node major `24`. These are its selected versions, not a claim that they are
119
+ the latest security releases. Use your platform's reviewed compatible versions
120
+ when updating an existing app. The CLI and build path check the platform's exact
121
+ approved Next/React selection; a different patch needs a coordinated platform
122
+ update, even if it belongs to the same framework profile.
123
+
124
+ For an approved patch, update the dependency declarations and lockfile together,
125
+ run the local type/build checks, then verify a hosted preview before requesting
126
+ an official repository-backed deployment. Existing immutable deployments keep
127
+ their previous code until rebuilt and activated. Your platform team maintains
128
+ build/runtime images and handles any urgent security response; this workflow
129
+ does not require application authors to obtain cloud-provider credentials.
130
+
131
+ ## Images and fonts
132
+
133
+ Keep static images and other binary assets in `public/`. Prefer committed WOFF2
134
+ fonts loaded with `next/font/local`; compilation runs without unrestricted
135
+ network access.
136
+
137
+ For a public font prepared by the platform, add `build.public_fonts` entries with
138
+ `path`, `url` and the actual lowercase `sha256` digest. Targets must be
139
+ `public/fonts/<filename>.woff2`, without nested directories. Use ASCII
140
+ letters/digits, hyphens or underscores for the basename, starting with a letter
141
+ or digit. URLs must use HTTPS on `fonts.gstatic.com` with its versioned
142
+ `/s/<family>/v<revision>/<file>.woff2` format and no query, fragment or custom
143
+ port. The platform allows
144
+ up to eight files, 2 MiB each and 8 MiB total, with no redirects. Connected local
145
+ development prepares the same files. Existing matching files are reused;
146
+ mismatches fail without overwriting your file. Load the result with
147
+ `next/font/local`. A plain `pnpm build` uses files already present locally and
148
+ does not prepare declared fonts. Do not use `next/font/google` to download during the
149
+ network-blocked compilation stage.
150
+
151
+ For a remote optimized image, add the exact HTTPS host to both Next's
152
+ `images.remotePatterns` and the manifest's `server.egress`. Narrow the pathname
153
+ to the content needed by the app. Wildcard hosts, custom ports, redirects,
154
+ custom loaders, SVG optimization and private-IP destinations are unsupported.
155
+ Remote bodies are capped at 10 MiB, or a lower configured limit. Keep the
156
+ `withArtifactNextConfig` wrapper in place and verify remote images in a hosted
157
+ preview under the application's actual egress policy.
@@ -0,0 +1,26 @@
1
+ import Link from 'next/link'
2
+
3
+ export default function AboutPage() {
4
+ return (
5
+ <main className="mx-auto max-w-3xl px-roomy py-10 sm:px-8">
6
+ <Link href="/" className="text-sm font-medium text-primary underline-offset-4 hover:underline">
7
+ Back to your application
8
+ </Link>
9
+ <h1 className="mb-6 mt-8 text-2xl font-semibold">One application, two runtimes</h1>
10
+ <div className="space-y-4 text-foreground-secondary">
11
+ <p>
12
+ Server Components, actions and route handlers execute on your local
13
+ Next.js process during development and in the managed runtime after deployment.
14
+ </p>
15
+ <p>
16
+ Client Components provide interactive UI in the browser. Import Atlas UI
17
+ components from a client module and use the server SDK only in server code.
18
+ </p>
19
+ <p>
20
+ Atlas controls access, resource bindings and deployment. Local development
21
+ uses explicit nonproduction bindings; managed secrets stay in hosted runtimes.
22
+ </p>
23
+ </div>
24
+ </main>
25
+ )
26
+ }
@@ -0,0 +1,18 @@
1
+ 'use server'
2
+
3
+ export interface GreetingState {
4
+ message: string
5
+ error: string | null
6
+ }
7
+
8
+ export async function greet(
9
+ _previousState: GreetingState,
10
+ formData: FormData,
11
+ ): Promise<GreetingState> {
12
+ const input = formData.get('name')
13
+ const name = typeof input === 'string' ? input.trim() : ''
14
+ if (name.length === 0 || name.length > 80) {
15
+ return { message: '', error: 'Enter a name between 1 and 80 characters.' }
16
+ }
17
+ return { message: `Hello, ${name}. Your server action ran successfully.`, error: null }
18
+ }
@@ -0,0 +1,6 @@
1
+ export function GET() {
2
+ return Response.json(
3
+ { ok: true, framework: 'nextjs' },
4
+ { headers: { 'Cache-Control': 'no-store' } },
5
+ )
6
+ }
@@ -0,0 +1,19 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+ import { Button } from '@sequenceholdings/atlas-ui/next'
5
+
6
+ export function Counter() {
7
+ const [count, setCount] = useState(0)
8
+
9
+ return (
10
+ <div className="flex items-center gap-stack-group">
11
+ <Button type="button" onClick={() => setCount(value => value + 1)}>
12
+ Increment
13
+ </Button>
14
+ <output className="font-mono text-lg tabular-nums" aria-live="polite">
15
+ {count}
16
+ </output>
17
+ </div>
18
+ )
19
+ }
@@ -0,0 +1,38 @@
1
+ 'use client'
2
+
3
+ import { useActionState } from 'react'
4
+ import { Button, Input } from '@sequenceholdings/atlas-ui/next'
5
+ import { greet, type GreetingState } from '../actions'
6
+
7
+ const initialState: GreetingState = { message: '', error: null }
8
+
9
+ export function GreetingForm() {
10
+ const [state, action, pending] = useActionState(greet, initialState)
11
+
12
+ return (
13
+ <form action={action} className="space-y-4">
14
+ <div className="space-y-2">
15
+ <label htmlFor="name" className="text-sm font-medium">Your name</label>
16
+ <Input
17
+ id="name"
18
+ name="name"
19
+ autoComplete="given-name"
20
+ required
21
+ maxLength={80}
22
+ aria-invalid={Boolean(state.error)}
23
+ aria-describedby="greeting-result"
24
+ />
25
+ </div>
26
+ <Button type="submit" disabled={pending}>
27
+ {pending ? 'Sending…' : 'Say hello'}
28
+ </Button>
29
+ <p
30
+ id="greeting-result"
31
+ aria-live="polite"
32
+ className={state.error ? 'text-sm text-destructive' : 'text-sm text-foreground-secondary'}
33
+ >
34
+ {state.error ?? state.message}
35
+ </p>
36
+ </form>
37
+ )
38
+ }
@@ -0,0 +1,4 @@
1
+ @import "tailwindcss";
2
+ @import "@sequenceholdings/atlas-ui/tokens.css";
3
+
4
+ @source "../node_modules/@sequenceholdings/atlas-ui/dist";
@@ -0,0 +1,27 @@
1
+ import type { Metadata } from 'next'
2
+ import { headers } from 'next/headers'
3
+ import type { ReactNode } from 'react'
4
+ import {
5
+ getArtifactBrowserBootstrap,
6
+ getArtifactRequestContext,
7
+ } from '@sequenceholdings/artifact-studio/server'
8
+ import { Providers } from './providers'
9
+ import './globals.css'
10
+
11
+ export const metadata: Metadata = {
12
+ title: '{{title}}',
13
+ description: 'A full-stack application managed by Atlas',
14
+ }
15
+
16
+ export default async function RootLayout({ children }: { children: ReactNode }) {
17
+ const context = await getArtifactRequestContext({ headers: await headers() })
18
+ const bootstrap = context ? getArtifactBrowserBootstrap(context) : null
19
+
20
+ return (
21
+ <html lang="en" className={bootstrap?.initialContext.theme?.dark ? 'dark' : undefined}>
22
+ <body className="min-h-screen bg-background font-sans text-foreground antialiased">
23
+ <Providers bootstrap={bootstrap}>{children}</Providers>
24
+ </body>
25
+ </html>
26
+ )
27
+ }
@@ -0,0 +1,51 @@
1
+ import Link from 'next/link'
2
+ import { connection } from 'next/server'
3
+ import { Counter } from './components/counter'
4
+ import { GreetingForm } from './components/greeting-form'
5
+
6
+ export default async function HomePage() {
7
+ await connection()
8
+ const renderedAt = new Date().toISOString()
9
+
10
+ return (
11
+ <main className="mx-auto max-w-5xl px-roomy py-10 sm:px-8">
12
+ <header className="mb-10 border-b border-border pb-8">
13
+ <p className="mb-3 text-xs font-semibold uppercase tracking-widest text-primary">
14
+ Artifact Studio / Next.js
15
+ </p>
16
+ <h1 className="text-3xl font-semibold tracking-tight">{{title}}</h1>
17
+ <p className="mt-3 max-w-2xl text-foreground-secondary">
18
+ Build your interface and server together. Develop on your machine,
19
+ preview in Atlas and publish an application that runs independently.
20
+ </p>
21
+ </header>
22
+
23
+ <div className="grid gap-stack-section md:grid-cols-2">
24
+ <section className="rounded-lg border border-border bg-card p-6" aria-labelledby="client-heading">
25
+ <h2 id="client-heading" className="text-lg font-semibold">Client interaction</h2>
26
+ <p className="mb-6 mt-2 text-sm text-muted-foreground">
27
+ Increment the counter, then edit its label. Fast Refresh preserves
28
+ client state for compatible edits.
29
+ </p>
30
+ <Counter />
31
+ </section>
32
+
33
+ <section className="rounded-lg border border-border bg-card p-6" aria-labelledby="server-heading">
34
+ <h2 id="server-heading" className="text-lg font-semibold">Server action</h2>
35
+ <p className="mb-6 mt-2 text-sm text-muted-foreground">
36
+ Submit a name to a validated server action. This example does not
37
+ store data or require a connected resource.
38
+ </p>
39
+ <GreetingForm />
40
+ </section>
41
+ </div>
42
+
43
+ <footer className="mt-8 flex flex-wrap items-center justify-between gap-stack-group text-sm text-muted-foreground">
44
+ <p>Rendered on the server: <time dateTime={renderedAt}>{renderedAt}</time></p>
45
+ <Link href="/about" className="font-medium text-primary underline-offset-4 hover:underline">
46
+ How this application works
47
+ </Link>
48
+ </footer>
49
+ </main>
50
+ )
51
+ }
@@ -0,0 +1,107 @@
1
+ 'use client'
2
+
3
+ import { Suspense, useEffect, useRef, useState, type ReactNode } from 'react'
4
+ import { usePathname, useRouter, useSearchParams } from 'next/navigation'
5
+ import { PortalContainerProvider } from '@sequenceholdings/atlas-ui/next'
6
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
7
+ import {
8
+ createNextArtifactBridge,
9
+ createNextArtifactThemeApplier,
10
+ installNextArtifactBrowserIntegration,
11
+ type NextArtifactBridge,
12
+ type NextArtifactBridgeBootstrap,
13
+ type NextArtifactInitialContext,
14
+ } from '@sequenceholdings/artifact-studio/next'
15
+
16
+ type BrowserBootstrap = NextArtifactBridgeBootstrap & {
17
+ initialContext: NextArtifactInitialContext
18
+ }
19
+
20
+ export function Providers({ children, bootstrap }: {
21
+ children: ReactNode
22
+ bootstrap: BrowserBootstrap | null
23
+ }) {
24
+ const [queryClient] = useState(() => new QueryClient())
25
+
26
+ return (
27
+ <QueryClientProvider client={queryClient}>
28
+ <PortalContainerProvider>
29
+ <Suspense fallback={null}>
30
+ <AtlasConnection bootstrap={bootstrap} />
31
+ </Suspense>
32
+ {children}
33
+ </PortalContainerProvider>
34
+ </QueryClientProvider>
35
+ )
36
+ }
37
+
38
+ function AtlasConnection({ bootstrap }: { bootstrap: BrowserBootstrap | null }) {
39
+ const router = useRouter()
40
+ const pathname = usePathname()
41
+ const searchParams = useSearchParams()
42
+ const currentBridge = useRef<NextArtifactBridge | null>(null)
43
+ const [connectionError, setConnectionError] = useState(false)
44
+
45
+ useEffect(() => {
46
+ if (!bootstrap) return
47
+ let active = true
48
+ const theme = createNextArtifactThemeApplier({ root: document.documentElement })
49
+ const bridge = createNextArtifactBridge({
50
+ bootstrap,
51
+ initialContext: bootstrap.initialContext,
52
+ onNavigate: ({ path, replace }) => replace ? router.replace(path) : router.push(path),
53
+ })
54
+ currentBridge.current = bridge
55
+ const removeBrowserIntegration = installNextArtifactBrowserIntegration({ bridge })
56
+ const applyTheme = () => {
57
+ const snapshot = bridge.getSnapshot()
58
+ if (snapshot.theme) theme.apply({ theme: snapshot.theme })
59
+ }
60
+ const updateRoute = () => bridge.routeChanged({
61
+ path: `${window.location.pathname}${window.location.search}${window.location.hash}`,
62
+ })
63
+ const updateTitle = () => {
64
+ if (bridge.getSnapshot().status === 'ready') {
65
+ bridge.setDocumentTitle({ label: document.title })
66
+ }
67
+ }
68
+ applyTheme()
69
+ const unsubscribe = bridge.subscribe(applyTheme)
70
+ const titleObserver = new MutationObserver(updateTitle)
71
+ titleObserver.observe(document.head, { childList: true, characterData: true, subtree: true })
72
+ window.addEventListener('hashchange', updateRoute)
73
+ updateRoute()
74
+ void bridge.connect().then(() => {
75
+ if (!active) return
76
+ setConnectionError(false)
77
+ updateTitle()
78
+ }).catch(() => {
79
+ if (active) setConnectionError(true)
80
+ })
81
+
82
+ return () => {
83
+ active = false
84
+ window.removeEventListener('hashchange', updateRoute)
85
+ titleObserver.disconnect()
86
+ unsubscribe()
87
+ removeBrowserIntegration()
88
+ bridge.dispose()
89
+ theme.dispose()
90
+ currentBridge.current = null
91
+ }
92
+ }, [bootstrap, router])
93
+
94
+ useEffect(() => {
95
+ const query = searchParams.toString()
96
+ currentBridge.current?.routeChanged({
97
+ path: `${pathname}${query ? `?${query}` : ''}${window.location.hash}`,
98
+ })
99
+ }, [pathname, searchParams])
100
+
101
+ if (!connectionError) return null
102
+ return (
103
+ <p role="alert" className="border-b border-border bg-card px-roomy py-default text-sm text-destructive">
104
+ The Atlas connection was interrupted. Reopen this preview from Artifact Studio.
105
+ </p>
106
+ )
107
+ }
@@ -0,0 +1,55 @@
1
+ bundle:
2
+ name: {{slug}}
3
+ schema_version: 2
4
+
5
+ artifact:
6
+ project_id: {{slug}}
7
+ title: "{{title}}"
8
+ description: "A full-stack Next.js application managed by Atlas"
9
+ type: nextjs
10
+ app_root: .
11
+
12
+ runtime:
13
+ sdk: sequence
14
+ react: 19
15
+ node: 24
16
+ next: '16.3'
17
+
18
+ # Browser permissions and server permissions are separate declarations.
19
+ capabilities:
20
+ data:
21
+ read: []
22
+ write: []
23
+ api:
24
+ read: []
25
+ write: []
26
+ functions:
27
+ invoke: []
28
+
29
+ server:
30
+ capabilities:
31
+ data:
32
+ read: []
33
+ write: []
34
+ api:
35
+ read: []
36
+ write: []
37
+ functions:
38
+ invoke: []
39
+ secrets: []
40
+ egress: []
41
+ resources:
42
+ cpu: 1
43
+ memory_mb: 1024
44
+ concurrency: 20
45
+ min_instances: 0
46
+ max_instances: 3
47
+ timeout_seconds: 60
48
+
49
+ build:
50
+ public_env: {}
51
+
52
+ # Add a registered Atlas environment with `seq-studio artifact link -e <env>`.
53
+ targets:
54
+ local:
55
+ url: http://localhost:5001
@@ -0,0 +1,9 @@
1
+ node_modules/
2
+ .next/
3
+ next-env.d.ts
4
+ .artifact/
5
+ .artifact-studio/
6
+ .env*
7
+ *.tsbuildinfo
8
+ coverage/
9
+ .DS_Store
@@ -0,0 +1,27 @@
1
+ import { withArtifactNextConfig } from '@sequenceholdings/artifact-studio/next-cache/config'
2
+
3
+ const devOrigin = process.env.ARTIFACT_STUDIO_DEV_ORIGIN
4
+
5
+ function allowedDevOrigins() {
6
+ if (!devOrigin) return []
7
+ const url = new URL(devOrigin)
8
+ if (
9
+ !['http:', 'https:'].includes(url.protocol) ||
10
+ url.username || url.password || url.pathname !== '/' || url.search || url.hash ||
11
+ url.hostname.includes('*')
12
+ ) {
13
+ throw new Error('ARTIFACT_STUDIO_DEV_ORIGIN must be an exact HTTP(S) origin.')
14
+ }
15
+ // Next matches hostnames; the Atlas gateway validates the complete origin.
16
+ return [url.hostname]
17
+ }
18
+
19
+ /** @type {import('next').NextConfig} */
20
+ const config = {
21
+ output: 'standalone',
22
+ poweredByHeader: false,
23
+ reactStrictMode: true,
24
+ allowedDevOrigins: allowedDevOrigins(),
25
+ }
26
+
27
+ export default withArtifactNextConfig(config)
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "{{slug}}",
3
+ "private": true,
4
+ "type": "module",
5
+ "packageManager": "pnpm@10.28.2",
6
+ "engines": {
7
+ "node": ">=24 <25"
8
+ },
9
+ "scripts": {
10
+ "dev": "next dev --webpack --hostname 127.0.0.1",
11
+ "build": "next build",
12
+ "start": "next start --hostname 127.0.0.1",
13
+ "type-check": "next typegen && tsc --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "@sequenceholdings/artifact-studio": "{{artifactStudioVersion}}",
17
+ "@sequenceholdings/atlas-ui": "3.4.0",
18
+ "@tanstack/react-query": "^4.36.1",
19
+ "next": "16.3.4",
20
+ "react": "19.2.6",
21
+ "react-dom": "19.2.6",
22
+ "server-only": "0.0.1"
23
+ },
24
+ "devDependencies": {
25
+ "@tailwindcss/postcss": "^4.2.2",
26
+ "@types/node": "^24.0.0",
27
+ "@types/react": "^19.2.10",
28
+ "@types/react-dom": "^19.2.3",
29
+ "tailwindcss": "^4.2.2",
30
+ "typescript": "^5.6.0"
31
+ }
32
+ }
@@ -0,0 +1,22 @@
1
+ packages:
2
+ - '.'
3
+
4
+ minimumReleaseAge: 10080
5
+ # The Sequence SDK chain is published from the Studio repo's audited release
6
+ # pipeline, so a new artifact-studio release must install without waiting out
7
+ # the seven-day quarantine. Scoped to the exact first-party packages a fresh
8
+ # scaffold resolves, not @sequenceholdings/*.
9
+ minimumReleaseAgeExclude:
10
+ - '@sequenceholdings/artifact-studio'
11
+ - '@sequenceholdings/atlas-ui'
12
+ - '@sequenceholdings/custom-roles-manifest'
13
+ - '@sequenceholdings/lattice-form-renderer'
14
+ - '@sequenceholdings/orm'
15
+ - '@sequenceholdings/storage'
16
+ strictDepBuilds: true
17
+ allowBuilds:
18
+ '@tailwindcss/oxide': false
19
+ # Reached through the SDK's static builder and ORM tooling, never run by a
20
+ # Next.js app; its platform binary installs as an optional dependency.
21
+ esbuild: false
22
+ sharp: false
@@ -0,0 +1,5 @@
1
+ export default {
2
+ plugins: {
3
+ '@tailwindcss/postcss': {},
4
+ },
5
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [{ "name": "next" }]
17
+ },
18
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
19
+ "exclude": ["node_modules"]
20
+ }
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "dependencies": {},
11
11
  "devDependencies": {
12
- "@sequenceholdings/artifact-studio": "^0.2.4",
12
+ "@sequenceholdings/artifact-studio": "^0.3.0",
13
13
  "@sequenceholdings/atlas-ui": "^3.1.1",
14
14
  "@tailwindcss/postcss": "^4.2.2",
15
15
  "@tailwindcss/vite": "^4.2.2",