@springbrand/space 0.2.0-alpha.11 → 0.2.0-alpha.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/space",
3
- "version": "0.2.0-alpha.11",
3
+ "version": "0.2.0-alpha.14",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -10,7 +10,11 @@
10
10
  "access": "public"
11
11
  },
12
12
  "exports": {
13
- ".": "./src/index.ts"
13
+ ".": "./src/index.ts",
14
+ "./deployment-contract": "./src/space/deployment-contract.ts",
15
+ "./deploy-engine": "./src/space/deploy-engine.ts",
16
+ "./lazy-space-do": "./src/space/durable-object.ts",
17
+ "./preview-headers": "./src/space/preview-headers.ts"
14
18
  },
15
19
  "dependencies": {
16
20
  "@cloudflare/shell": "0.4.3",
@@ -20,11 +24,14 @@
20
24
  "devDependencies": {
21
25
  "@cloudflare/vitest-pool-workers": "^0.20.1",
22
26
  "@cloudflare/workers-types": "^4.20251008.0",
27
+ "esbuild": "0.28.1",
23
28
  "typescript": "^7.0.2",
24
29
  "vitest": "^4.1.10"
25
30
  },
26
31
  "scripts": {
32
+ "build": "node build.mjs",
27
33
  "check": "tsc --noEmit",
34
+ "pretest": "pnpm build",
28
35
  "test": "vitest run"
29
36
  }
30
37
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // ── Durable Object classes ────────────────────────────────────────
2
- export { SpaceDO } from "./space/durable-object";
2
+ export { SpaceDO } from "./space/default-durable-object";
3
3
 
4
4
  // ── RPC surface ───────────────────────────────────────────────────
5
5
  export type {
@@ -22,14 +22,14 @@ export { SPACE_RESERVED_PREFIXES } from "./space/durable-object";
22
22
  export {
23
23
  deploymentRuntimeConfigSource,
24
24
  RUNTIME_CONFIG_ASSET_PATH,
25
- } from "./space/deploy-engine";
25
+ } from "./space/deployment-contract";
26
26
  export type {
27
27
  BranchDeploymentBundle,
28
28
  DeploymentAsset,
29
29
  DeploymentBundle,
30
30
  DeploymentRuntimeConfig,
31
31
  SpaceDeploymentResult,
32
- } from "./space/deploy-engine";
32
+ } from "./space/deployment-contract";
33
33
 
34
34
  // ── Preview hardening ─────────────────────────────────────────────
35
35
  export { stripPreviewSecurityHeaders, STRIPPED_PREVIEW_HEADERS } from "./space/preview-headers";
@@ -0,0 +1,13 @@
1
+ import {
2
+ createSpaceDO,
3
+ type DeployEngine,
4
+ } from "./durable-object"
5
+
6
+ let deployEnginePromise: Promise<DeployEngine> | undefined
7
+
8
+ const DefaultSpaceDO = createSpaceDO(
9
+ () => deployEnginePromise ??= import("@springbrand/space/deploy-engine"),
10
+ )
11
+
12
+ export const SpaceDO = DefaultSpaceDO
13
+ export type SpaceDO = InstanceType<typeof DefaultSpaceDO>
@@ -1,5 +1,3 @@
1
- import type { Git } from "@cloudflare/shell/git"
2
- import type { FileSystem } from "@cloudflare/shell"
3
1
  import {
4
2
  createWorker,
5
3
  inferContentType,
@@ -7,6 +5,15 @@ import {
7
5
  type AssetConfig,
8
6
  type Modules,
9
7
  } from "@cloudflare/worker-bundler"
8
+ import {
9
+ deploymentRuntimeConfigSource,
10
+ RUNTIME_CONFIG_ASSET_PATH,
11
+ type BranchDeploymentBundle,
12
+ type DeployContext,
13
+ type DeploymentAsset,
14
+ type DeploymentRuntimeConfig,
15
+ type SpaceDeploymentResult,
16
+ } from "./deployment-contract"
10
17
  import { globInfos } from "./fileinfo"
11
18
  import {
12
19
  parseWranglerConfig,
@@ -14,6 +21,17 @@ import {
14
21
  WranglerConfigError,
15
22
  } from "./wrangler-config"
16
23
 
24
+ export {
25
+ deploymentRuntimeConfigSource,
26
+ RUNTIME_CONFIG_ASSET_PATH,
27
+ type BranchDeploymentBundle,
28
+ type DeployContext,
29
+ type DeploymentAsset,
30
+ type DeploymentBundle,
31
+ type DeploymentRuntimeConfig,
32
+ type SpaceDeploymentResult,
33
+ } from "./deployment-contract"
34
+
17
35
  // ─── Deploy Engine ──────────────────────────────────────────────────────────
18
36
 
19
37
  /** Shared JSON response helper for the internal deploy command handlers. */
@@ -24,53 +42,6 @@ function jsonResponse(data: unknown, status: number = 200): Response {
24
42
  })
25
43
  }
26
44
 
27
- export interface DeployContext {
28
- sql: SqlStorage
29
- git: Git
30
- fs: FileSystem
31
- assetBucket?: R2Bucket
32
- assetPrefix?: string
33
- }
34
-
35
- export interface DeploymentBundle {
36
- branch: string
37
- commitHash: string
38
- workerModules: {
39
- mainModule: string
40
- modules: Record<string, string | Record<string, unknown>>
41
- compatibilityDate: string
42
- }
43
- staticAssets: DeploymentAsset[]
44
- assetConfig: AssetConfig | undefined
45
- runtimeConfig: DeploymentRuntimeConfig | undefined
46
- }
47
-
48
- export type BranchDeploymentBundle = DeploymentBundle
49
-
50
- export interface DeploymentRuntimeConfig {
51
- apiBaseUrl: string
52
- }
53
-
54
- export interface SpaceDeploymentResult {
55
- branch: string
56
- commit_hash: string
57
- main_module: string
58
- has_assets: boolean
59
- compatibility_date: string
60
- deployed_at: string
61
- asset_root: string | null
62
- }
63
-
64
- export const RUNTIME_CONFIG_ASSET_PATH = "/.springbrand/runtime-config.js"
65
-
66
- export interface DeploymentAsset {
67
- path: string
68
- sourcePath: string | null
69
- contentType: string | undefined
70
- etag: string
71
- size: number
72
- }
73
-
74
45
  type AssetWriter = (
75
46
  asset: Omit<DeploymentAsset, "etag">,
76
47
  bytes: Uint8Array,
@@ -436,10 +407,6 @@ function normalizeRuntimeConfig(
436
407
  return { apiBaseUrl: url.toString() }
437
408
  }
438
409
 
439
- export function deploymentRuntimeConfigSource(config: DeploymentRuntimeConfig): string {
440
- return `globalThis.__APP_CONFIG__=Object.freeze(${JSON.stringify(config)});`
441
- }
442
-
443
410
  async function buildWebsite(
444
411
  sourceFiles: Record<string, string>,
445
412
  config: ParsedWranglerConfig,
@@ -0,0 +1,54 @@
1
+ import type { FileSystem } from "@cloudflare/shell"
2
+ import type { Git } from "@cloudflare/shell/git"
3
+ import type { AssetConfig } from "@cloudflare/worker-bundler"
4
+
5
+ export interface DeployContext {
6
+ sql: SqlStorage
7
+ git: Git
8
+ fs: FileSystem
9
+ assetBucket?: R2Bucket
10
+ assetPrefix?: string
11
+ }
12
+
13
+ export interface DeploymentBundle {
14
+ branch: string
15
+ commitHash: string
16
+ workerModules: {
17
+ mainModule: string
18
+ modules: Record<string, string | Record<string, unknown>>
19
+ compatibilityDate: string
20
+ }
21
+ staticAssets: DeploymentAsset[]
22
+ assetConfig: AssetConfig | undefined
23
+ runtimeConfig: DeploymentRuntimeConfig | undefined
24
+ }
25
+
26
+ export type BranchDeploymentBundle = DeploymentBundle
27
+
28
+ export interface DeploymentRuntimeConfig {
29
+ apiBaseUrl: string
30
+ }
31
+
32
+ export interface SpaceDeploymentResult {
33
+ branch: string
34
+ commit_hash: string
35
+ main_module: string
36
+ has_assets: boolean
37
+ compatibility_date: string
38
+ deployed_at: string
39
+ asset_root: string | null
40
+ }
41
+
42
+ export interface DeploymentAsset {
43
+ path: string
44
+ sourcePath: string | null
45
+ contentType: string | undefined
46
+ etag: string
47
+ size: number
48
+ }
49
+
50
+ export const RUNTIME_CONFIG_ASSET_PATH = "/.springbrand/runtime-config.js"
51
+
52
+ export function deploymentRuntimeConfigSource(config: DeploymentRuntimeConfig): string {
53
+ return `globalThis.__APP_CONFIG__=Object.freeze(${JSON.stringify(config)});`
54
+ }
@@ -2,14 +2,12 @@ import { DurableObject } from "cloudflare:workers"
2
2
  import { type FileSystem, type FileInfo } from "@cloudflare/shell"
3
3
  import { type Git, type GitLogEntry, type GitStatusEntry } from "@cloudflare/shell/git"
4
4
  import type { Env } from "../env"
5
- import {
6
- buildBranchDeployment,
7
- handleDeployCommand,
8
- type BranchDeploymentBundle,
9
- type DeploymentRuntimeConfig,
10
- type DeployContext,
11
- type SpaceDeploymentResult,
12
- } from "./deploy-engine"
5
+ import type {
6
+ BranchDeploymentBundle,
7
+ DeploymentRuntimeConfig,
8
+ DeployContext,
9
+ SpaceDeploymentResult,
10
+ } from "./deployment-contract"
13
11
  import { globInfos, readDirInfos, toFileInfo } from "./fileinfo"
14
12
  import {
15
13
  buildInspectorWrapperSource,
@@ -61,6 +59,9 @@ export type {
61
59
  /** The complete capability a host holds over one Space. */
62
60
  export type SpaceStub = SpaceWorkspacePort & SpaceControlPort & SpaceAppPort
63
61
 
62
+ export type DeployEngine = typeof import("@springbrand/space/deploy-engine")
63
+ export type DeployEngineLoader = () => Promise<DeployEngine>
64
+
64
65
  // ─── Inspector result types ────────────────────────────────────────────────
65
66
  // These mirror the shapes returned by the wrapper-subclass injected into
66
67
  // the dynamic worker (see `inspector-wrapper.ts`). Re-exported at the
@@ -110,7 +111,7 @@ const isReservedPath = isReservedSpacePath
110
111
  // Commits/deploys are mirrored to a per-app Cloudflare Artifacts repo
111
112
  // (see artifacts-sync.ts), which is the durable source of truth for history.
112
113
 
113
- export class SpaceDO extends DurableObject<Env>
114
+ export abstract class SpaceDOBase extends DurableObject<Env>
114
115
  implements SpaceWorkspacePort, SpaceControlPort, SpaceAppPort {
115
116
  private backend!: SpaceFsBackend
116
117
  private initializationPromise: Promise<void> | null = null
@@ -133,6 +134,8 @@ export class SpaceDO extends DurableObject<Env>
133
134
  super(ctx, env)
134
135
  }
135
136
 
137
+ protected abstract loadDeployEngine(): Promise<DeployEngine>
138
+
136
139
  private async flushCheckpoint(): Promise<void> {
137
140
  await this.backend.flushCheckpoint()
138
141
  }
@@ -1110,6 +1113,7 @@ export class SpaceDO extends DurableObject<Env>
1110
1113
  ): Promise<SpaceDeploymentResult> {
1111
1114
  await this.ensureInit()
1112
1115
  return this.lane(async () => {
1116
+ const { handleDeployCommand } = await this.loadDeployEngine()
1113
1117
  // The deploy engine reads the full branch tree, so ensure the Artifacts
1114
1118
  // base is materialized into the overlay first.
1115
1119
  await this.materializeAll()
@@ -1149,6 +1153,7 @@ export class SpaceDO extends DurableObject<Env>
1149
1153
  ): Promise<BranchDeploymentBundle> {
1150
1154
  await this.ensureInit()
1151
1155
  await this.materializeAll()
1156
+ const { buildBranchDeployment } = await this.loadDeployEngine()
1152
1157
  return buildBranchDeployment(
1153
1158
  {
1154
1159
  sql: this.ctx.storage.sql,
@@ -1165,6 +1170,7 @@ export class SpaceDO extends DurableObject<Env>
1165
1170
 
1166
1171
  async undeploy(branch: string): Promise<unknown> {
1167
1172
  await this.ensureInit()
1173
+ const { handleDeployCommand } = await this.loadDeployEngine()
1168
1174
  const fakeRequest = new Request("http://internal/?cmd=undeploy", {
1169
1175
  method: "POST",
1170
1176
  headers: { "Content-Type": "application/json" },
@@ -1183,6 +1189,7 @@ export class SpaceDO extends DurableObject<Env>
1183
1189
 
1184
1190
  async listDeployments(): Promise<unknown> {
1185
1191
  await this.ensureInit()
1192
+ const { handleDeployCommand } = await this.loadDeployEngine()
1186
1193
  const fakeRequest = new Request("http://internal/?cmd=list_deployments")
1187
1194
  const ctx: DeployContext = {
1188
1195
  sql: this.ctx.storage.sql,
@@ -1195,6 +1202,7 @@ export class SpaceDO extends DurableObject<Env>
1195
1202
 
1196
1203
  async getDeployment(branch: string): Promise<unknown> {
1197
1204
  await this.ensureInit()
1205
+ const { handleDeployCommand } = await this.loadDeployEngine()
1198
1206
  const fakeRequest = new Request(`http://internal/?cmd=get_deployment&branch=${encodeURIComponent(branch)}`)
1199
1207
  const ctx: DeployContext = {
1200
1208
  sql: this.ctx.storage.sql,
@@ -1392,6 +1400,7 @@ export class SpaceDO extends DurableObject<Env>
1392
1400
 
1393
1401
  const cmd = new URL(request.url).searchParams.get("cmd")
1394
1402
  if (cmd && ["deploy", "get_deployment", "list_deployments", "undeploy"].includes(cmd)) {
1403
+ const { handleDeployCommand } = await this.loadDeployEngine()
1395
1404
  const deployCtx: DeployContext = {
1396
1405
  sql: this.ctx.storage.sql,
1397
1406
  git: this.git,
@@ -1406,6 +1415,14 @@ export class SpaceDO extends DurableObject<Env>
1406
1415
  }
1407
1416
  }
1408
1417
 
1418
+ export function createSpaceDO(loadDeployEngine: DeployEngineLoader): typeof SpaceDOBase {
1419
+ return class SpaceDO extends SpaceDOBase {
1420
+ protected loadDeployEngine(): Promise<DeployEngine> {
1421
+ return loadDeployEngine()
1422
+ }
1423
+ }
1424
+ }
1425
+
1409
1426
  // ─── Facet naming ───────────────────────────────────────────────────────────
1410
1427
 
1411
1428
  function facetNameForApp(branch: string): string {
@@ -0,0 +1 @@
1
+ export * from "@springbrand/space/deploy-engine"