ignotum 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/bin.mjs CHANGED
@@ -29658,6 +29658,7 @@ const Sha256 = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/)).pipe(Sche
29658
29658
  const ArtifactKind = Schema.Literals([
29659
29659
  "ClientAsset",
29660
29660
  "ClientDocument",
29661
+ "ClientManifest",
29661
29662
  "ClientPublicFile",
29662
29663
  "ClientShell",
29663
29664
  "FunctionBundle",
@@ -29680,13 +29681,26 @@ const ArtifactFile = Schema.Struct({
29680
29681
  });
29681
29682
  const ClientRoute = Schema.Struct({
29682
29683
  pathname: ClientPath,
29683
- artifact: ArtifactPath
29684
+ artifact: ArtifactReference
29684
29685
  });
29685
29686
  const DeploymentInventory = Schema.Struct({
29686
29687
  formatVersion: Schema.Literal(1),
29687
- client: Schema.Struct({ routes: Schema.Array(ClientRoute) }),
29688
29688
  files: Schema.Array(ArtifactFile)
29689
29689
  });
29690
+ const ClientManifest = Schema.Struct({
29691
+ formatVersion: Schema.Literal(1),
29692
+ shell: ArtifactReference,
29693
+ routes: Schema.Array(ClientRoute)
29694
+ });
29695
+ const ClientRoutingRoute = Schema.Struct({
29696
+ pathname: ClientPath,
29697
+ artifact: ArtifactPath
29698
+ });
29699
+ Schema.Struct({
29700
+ formatVersion: Schema.Literal(1),
29701
+ shell: ArtifactPath,
29702
+ routes: Schema.Array(ClientRoutingRoute)
29703
+ });
29690
29704
  const SchemaSnapshotField = Schema.Struct({
29691
29705
  name: Schema.String,
29692
29706
  value: ValueDescriptor
@@ -29711,8 +29725,10 @@ const ServerBuildManifest = Schema.Struct({
29711
29725
  functions: Schema.Array(ServerFunctionArtifact)
29712
29726
  });
29713
29727
  const deploymentInventoryPath = ArtifactPath.make("inventory.json");
29714
- const clientShellPath = ArtifactPath.make("client/_shell.html");
29715
- const clientAssetPathPrefix = `${ArtifactPath.make("client/_ignotum/assets")}/`;
29728
+ const clientManifestPath = ArtifactPath.make("client/manifest.json");
29729
+ const clientShellPath = ArtifactPath.make("client/shell.html");
29730
+ const clientAssetPathPrefix = `${ArtifactPath.make("client/assets")}/`;
29731
+ const clientRoutePathPrefix = `${ArtifactPath.make("client/routes")}/`;
29716
29732
  const clientPublicFileExtensions = [
29717
29733
  ".avif",
29718
29734
  ".gif",
@@ -29823,7 +29839,7 @@ var IdGenerator = class IdGenerator extends Context.Service()("@ignotum/shared/i
29823
29839
  };
29824
29840
  //#endregion
29825
29841
  //#region package.json
29826
- var version = "0.0.5";
29842
+ var version = "0.0.6";
29827
29843
  //#endregion
29828
29844
  //#region src/cli/codegen.ts
29829
29845
  const generatedHeader = "// Generated by `ignotum codegen`. Do not edit.";
@@ -30221,11 +30237,11 @@ const contentType = (path) => {
30221
30237
  };
30222
30238
  const isClientPublicFile = (path) => clientPublicFileExtensions.some((extension) => path.toLowerCase().endsWith(extension));
30223
30239
  const artifactKind = (path) => {
30240
+ if (path === clientManifestPath) return "ClientManifest";
30224
30241
  if (path === clientShellPath) return "ClientShell";
30225
30242
  if (path.startsWith(clientAssetPathPrefix)) return "ClientAsset";
30226
- if (path.startsWith("client/_ignotum/")) return void 0;
30227
- if (path.startsWith("client/") && path.endsWith(".html")) return "ClientDocument";
30228
- if (path.startsWith("client/") && isClientPublicFile(path)) return "ClientPublicFile";
30243
+ if (path.startsWith(clientRoutePathPrefix) && path.endsWith(".html")) return "ClientDocument";
30244
+ if (path.startsWith(clientRoutePathPrefix) && isClientPublicFile(path)) return "ClientPublicFile";
30229
30245
  if (path === serverManifestPath) return "ServerManifest";
30230
30246
  if (path === schemaSnapshotPath) return "SchemaSnapshot";
30231
30247
  if (path.startsWith("server/functions/") && path.endsWith(".mjs.map")) return "SourceMap";
@@ -30242,18 +30258,16 @@ const makeArtifactFile = Effect.fn("Deployment.makeArtifactFile")(function* (inp
30242
30258
  contentType: contentType(input.path)
30243
30259
  };
30244
30260
  });
30245
- const makeInventoryFromNormalized = Effect.fn("Deployment.makeInventoryFromNormalized")(function* (files, routes) {
30261
+ const makeInventoryFromNormalized = Effect.fn("Deployment.makeInventoryFromNormalized")(function* (files) {
30246
30262
  const inventoryFiles = yield* Effect.forEach(files, makeArtifactFile, { concurrency: "unbounded" });
30247
30263
  return {
30248
30264
  formatVersion: 1,
30249
- client: { routes: Array$1.sortWith(routes, (route) => route.pathname, String$1.Order) },
30250
30265
  files: Array$1.sortWith(inventoryFiles, (file) => file.path, String$1.Order)
30251
30266
  };
30252
30267
  });
30253
30268
  const validateDeploymentInventory = Effect.fn("Deployment.validateDeploymentInventory")(function* (inventory) {
30254
30269
  if (inventory.files.length > deploymentArtifactLimits.fileCount) return yield* invalid$3(`Deployment inventories may contain at most ${deploymentArtifactLimits.fileCount} files.`);
30255
30270
  const paths = /* @__PURE__ */ new Set();
30256
- const entries = /* @__PURE__ */ new Map();
30257
30271
  let previousPath;
30258
30272
  let serverBytes = 0;
30259
30273
  let totalBytes = 0;
@@ -30267,34 +30281,22 @@ const validateDeploymentInventory = Effect.fn("Deployment.validateDeploymentInve
30267
30281
  }
30268
30282
  if (paths.has(file.path)) return yield* invalid$3(`Duplicate deployment inventory path '${file.path}'.`, file.path);
30269
30283
  paths.add(file.path);
30270
- entries.set(file.path, file);
30271
30284
  if (previousPath !== void 0 && String$1.Order(previousPath, file.path) >= 0) return yield* invalid$3("Deployment inventory files must be sorted by path.", file.path);
30272
30285
  previousPath = file.path;
30273
30286
  const expectedKind = artifactKind(file.path);
30274
30287
  if (expectedKind === void 0 || expectedKind !== file.kind) return yield* invalid$3(`Deployment inventory kind '${file.kind}' does not match '${file.path}'.`, file.path);
30275
30288
  }
30276
- for (const path of [serverManifestPath, schemaSnapshotPath]) if (!paths.has(path)) return yield* invalid$3(`Artifact file '${path}' is missing.`, path);
30277
- const routedArtifacts = /* @__PURE__ */ new Map();
30278
- let previousRoute;
30279
- for (const route of inventory.client.routes) {
30280
- if (previousRoute !== void 0 && String$1.Order(previousRoute, route.pathname) >= 0) return yield* invalid$3("Client routes must be sorted by pathname.", route.pathname);
30281
- previousRoute = route.pathname;
30282
- const entry = entries.get(route.artifact);
30283
- if (entry === void 0) return yield* invalid$3(`Client route '${route.pathname}' references missing artifact '${route.artifact}'.`, route.artifact);
30284
- if (entry.kind !== "ClientDocument" && entry.kind !== "ClientPublicFile") return yield* invalid$3(`Client route '${route.pathname}' cannot reference artifact kind '${entry.kind}'.`, route.artifact);
30285
- routedArtifacts.set(route.artifact, (routedArtifacts.get(route.artifact) ?? 0) + 1);
30286
- }
30287
- for (const file of inventory.files) {
30288
- const routeCount = routedArtifacts.get(file.path) ?? 0;
30289
- if (file.kind === "ClientDocument" && routeCount === 0) return yield* invalid$3(`Client document '${file.path}' has no route.`, file.path);
30290
- if (file.kind === "ClientPublicFile" && routeCount !== 1) return yield* invalid$3(`Client public file '${file.path}' must have exactly one route.`, file.path);
30291
- }
30292
- if (!paths.has(clientShellPath) && inventory.client.routes.length === 0) return yield* invalid$3("A deployment must contain a client shell or an exact client route.");
30289
+ for (const path of [
30290
+ clientManifestPath,
30291
+ clientShellPath,
30292
+ serverManifestPath,
30293
+ schemaSnapshotPath
30294
+ ]) if (!paths.has(path)) return yield* invalid$3(`Artifact file '${path}' is missing.`, path);
30293
30295
  });
30294
- const makeDeploymentInventory = Effect.fn("Deployment.makeDeploymentInventory")(function* (inputs, routes = []) {
30296
+ const makeDeploymentInventory = Effect.fn("Deployment.makeDeploymentInventory")(function* (inputs) {
30295
30297
  const files = yield* normalizeFiles(inputs);
30296
30298
  if (files.some((file) => file.path === deploymentInventoryPath)) return yield* invalid$3(`${deploymentInventoryPath} cannot include itself in the deployment inventory.`, deploymentInventoryPath);
30297
- const inventory = yield* makeInventoryFromNormalized(files, routes);
30299
+ const inventory = yield* makeInventoryFromNormalized(files);
30298
30300
  const encoded = `${encodeCanonical(DeploymentInventory, inventory)}\n`;
30299
30301
  return {
30300
30302
  inventory,
@@ -30317,6 +30319,24 @@ const findFile = (files, path) => {
30317
30319
  return file === void 0 ? Effect.fail(invalid$3(`Artifact file '${path}' is missing.`, path)) : Effect.succeed(file);
30318
30320
  };
30319
30321
  const sameReference = (entry, reference) => entry.path === reference.path && entry.size === reference.size && entry.sha256 === reference.sha256;
30322
+ const validateClientManifest = Effect.fn("Deployment.validateClientManifest")(function* (manifest, inventory) {
30323
+ if (manifest.shell.path !== clientShellPath) return yield* invalid$3(`The client manifest must reference '${clientShellPath}' as its shell.`, manifest.shell.path);
30324
+ const entries = new Map(inventory.files.map((file) => [file.path, file]));
30325
+ const shellEntry = entries.get(manifest.shell.path);
30326
+ if (shellEntry === void 0 || shellEntry.kind !== "ClientShell" || !sameReference(shellEntry, manifest.shell)) return yield* invalid$3(`The client shell reference for '${manifest.shell.path}' does not match the inventory.`, manifest.shell.path);
30327
+ const referencedPaths = /* @__PURE__ */ new Set();
30328
+ let previousRoute;
30329
+ for (const route of manifest.routes) {
30330
+ if (previousRoute !== void 0 && String$1.Order(previousRoute, route.pathname) >= 0) return yield* invalid$3("Client routes must be sorted by pathname.", route.pathname);
30331
+ previousRoute = route.pathname;
30332
+ if (referencedPaths.has(route.artifact.path)) return yield* invalid$3(`Client artifact path '${route.artifact.path}' is referenced more than once.`, route.artifact.path);
30333
+ referencedPaths.add(route.artifact.path);
30334
+ const entry = entries.get(route.artifact.path);
30335
+ if (entry === void 0 || !sameReference(entry, route.artifact)) return yield* invalid$3(`The client route reference for '${route.artifact.path}' does not match the inventory.`, route.artifact.path);
30336
+ if (entry.kind !== "ClientDocument" && entry.kind !== "ClientPublicFile") return yield* invalid$3(`Client route '${route.pathname}' cannot reference artifact kind '${entry.kind}'.`, route.artifact.path);
30337
+ }
30338
+ for (const file of inventory.files) if ((file.kind === "ClientDocument" || file.kind === "ClientPublicFile") && !referencedPaths.has(file.path)) return yield* invalid$3(`Client route artifact '${file.path}' has no route.`, file.path);
30339
+ });
30320
30340
  const validateManifest = Effect.fn("Deployment.validateManifest")(function* (manifest, inventory) {
30321
30341
  if (manifest.schema.path !== schemaSnapshotPath) return yield* invalid$3(`The server manifest must reference '${schemaSnapshotPath}'.`, manifest.schema.path);
30322
30342
  const entries = new Map(inventory.files.map((file) => [file.path, file]));
@@ -30357,17 +30377,28 @@ Effect.fn("Deployment.validateDeploymentMetadata")(function* (input) {
30357
30377
  path: schemaSnapshotPath,
30358
30378
  bytes: input.schemaBytes
30359
30379
  };
30360
- const metadataFiles = [manifestFile, schemaFile];
30380
+ const clientManifestFile = {
30381
+ path: clientManifestPath,
30382
+ bytes: input.clientManifestBytes
30383
+ };
30384
+ const metadataFiles = [
30385
+ clientManifestFile,
30386
+ manifestFile,
30387
+ schemaFile
30388
+ ];
30361
30389
  const entries = new Map(input.inventory.files.map((file) => [file.path, file]));
30362
30390
  for (const file of metadataFiles) {
30363
30391
  const entry = entries.get(file.path);
30364
30392
  const actual = yield* makeArtifactFile(file);
30365
30393
  if (entry === void 0 || encodeCanonical(ArtifactFile, actual) !== encodeCanonical(ArtifactFile, entry)) return yield* invalid$3(`Artifact file '${file.path}' does not match the deployment inventory.`, file.path);
30366
30394
  }
30395
+ const clientManifest = yield* decodeJsonFile(ClientManifest, clientManifestFile);
30367
30396
  const manifest = yield* decodeJsonFile(ServerBuildManifest, manifestFile);
30368
30397
  const schema = yield* decodeJsonFile(SchemaSnapshot, schemaFile);
30398
+ yield* validateClientManifest(clientManifest, input.inventory);
30369
30399
  yield* validateManifest(manifest, input.inventory);
30370
30400
  return {
30401
+ clientManifest,
30371
30402
  inventory: input.inventory,
30372
30403
  manifest,
30373
30404
  schema
@@ -30379,14 +30410,18 @@ const validateDeploymentArtifact = Effect.fn("Deployment.validateDeploymentArtif
30379
30410
  const payloadFiles = files.filter((file) => file.path !== deploymentInventoryPath);
30380
30411
  const inventory = yield* decodeJsonFile(DeploymentInventory, inventoryFile);
30381
30412
  yield* validateDeploymentInventory(inventory);
30382
- const actualInventory = yield* makeInventoryFromNormalized(payloadFiles, inventory.client.routes);
30413
+ const actualInventory = yield* makeInventoryFromNormalized(payloadFiles);
30383
30414
  if (encodeCanonical(DeploymentInventory, inventory) !== encodeCanonical(DeploymentInventory, actualInventory)) return yield* invalid$3("The deployment inventory does not match the artifact files.");
30415
+ const clientManifestFile = yield* findFile(files, clientManifestPath);
30384
30416
  const manifestFile = yield* findFile(files, serverManifestPath);
30385
30417
  const schemaFile = yield* findFile(files, schemaSnapshotPath);
30418
+ const clientManifest = yield* decodeJsonFile(ClientManifest, clientManifestFile);
30386
30419
  const manifest = yield* decodeJsonFile(ServerBuildManifest, manifestFile);
30387
30420
  const schema = yield* decodeJsonFile(SchemaSnapshot, schemaFile);
30421
+ yield* validateClientManifest(clientManifest, inventory);
30388
30422
  yield* validateManifest(manifest, inventory);
30389
30423
  return {
30424
+ clientManifest,
30390
30425
  inventory,
30391
30426
  manifest,
30392
30427
  schema
@@ -31001,10 +31036,10 @@ const copyPublicFiles = Effect.fn("Deploy.copyPublicFiles")(function* (appDirect
31001
31036
  const pathname = `/${relativePath}`;
31002
31037
  return {
31003
31038
  bytes,
31004
- destination: path.join(outputDirectory, entry),
31039
+ destination: path.join(outputDirectory, "routes", entry),
31005
31040
  route: {
31006
31041
  pathname: ClientPath.make(pathname),
31007
- artifact: ArtifactPath.make(`client/${relativePath}`)
31042
+ artifact: yield* artifactReference(ArtifactPath.make(`client/routes/${relativePath}`), bytes)
31008
31043
  },
31009
31044
  source
31010
31045
  };
@@ -31035,15 +31070,15 @@ const buildClient = Effect.fn("Deploy.buildClient")(function* (appDirectory, out
31035
31070
  const output = yield* runViteBuild("client", {
31036
31071
  appType: "spa",
31037
31072
  build: {
31038
- assetsDir: "_ignotum/assets",
31073
+ assetsDir: "assets",
31039
31074
  emptyOutDir: true,
31040
31075
  outDir: outputDirectory,
31041
31076
  rolldownOptions: {
31042
31077
  input: clientEntryId,
31043
31078
  output: {
31044
- assetFileNames: (asset) => asset.names.some((name) => name.endsWith(".css")) ? "_ignotum/assets/styles-[hash][extname]" : "_ignotum/assets/[name]-[hash][extname]",
31045
- chunkFileNames: "_ignotum/assets/chunks/[name]-[hash].js",
31046
- entryFileNames: "_ignotum/assets/main-[hash].js"
31079
+ assetFileNames: (asset) => asset.names.some((name) => name.endsWith(".css")) ? "assets/styles-[hash][extname]" : "assets/[name]-[hash][extname]",
31080
+ chunkFileNames: "assets/chunks/[name]-[hash].js",
31081
+ entryFileNames: "assets/main-[hash].js"
31047
31082
  }
31048
31083
  },
31049
31084
  sourcemap: false
@@ -31079,27 +31114,35 @@ const buildClient = Effect.fn("Deploy.buildClient")(function* (appDirectory, out
31079
31114
  let icon;
31080
31115
  if (clientFiles.iconPath !== void 0) {
31081
31116
  const bytes = yield* fileSystem.readFile(clientFiles.iconPath);
31082
- const fileName = `icon-${yield* sha256(bytes)}.svg`;
31083
- const assetsDirectory = path.join(outputDirectory, "_ignotum", "assets");
31117
+ const fileName = `icon-${(yield* sha256(bytes)).slice(0, 16)}.svg`;
31118
+ const assetsDirectory = path.join(outputDirectory, "assets");
31084
31119
  yield* fileSystem.makeDirectory(assetsDirectory, { recursive: true });
31085
31120
  yield* fileSystem.writeFile(path.join(assetsDirectory, fileName), bytes);
31086
31121
  icon = `/_ignotum/assets/${fileName}`;
31087
31122
  }
31088
- const shellPath = path.join(outputDirectory, "_shell.html");
31123
+ const shellPath = path.join(outputDirectory, "shell.html");
31089
31124
  const document = renderClientDocument({
31090
31125
  icon,
31091
31126
  scripts: [{
31092
- source: entryFile,
31127
+ source: `_ignotum/${entryFile}`,
31093
31128
  type: "External"
31094
31129
  }],
31095
- styles,
31130
+ styles: styles.map((style) => `_ignotum/${style}`),
31096
31131
  title
31097
31132
  });
31098
- yield* fileSystem.writeFileString(shellPath, document);
31133
+ const shellBytes = utf8Bytes(document);
31134
+ yield* fileSystem.writeFile(shellPath, shellBytes);
31099
31135
  const publicBuild = yield* copyPublicFiles(appDirectory, outputDirectory);
31136
+ const manifest = {
31137
+ formatVersion: 1,
31138
+ shell: yield* artifactReference(clientShellPath, shellBytes),
31139
+ routes: publicBuild.routes
31140
+ };
31141
+ const manifestPath = path.join(outputDirectory, "manifest.json");
31142
+ yield* fileSystem.writeFileString(manifestPath, `${encodeCanonical(ClientManifest, manifest)}\n`);
31100
31143
  return {
31101
31144
  assets: output.length + (icon === void 0 ? 0 : 1) + publicBuild.files,
31102
- routes: publicBuild.routes,
31145
+ manifestPath,
31103
31146
  shellPath
31104
31147
  };
31105
31148
  });
@@ -31495,7 +31538,7 @@ const buildDeploymentArtifact = Effect.fn("Deploy.buildArtifact")(function* (app
31495
31538
  const client = yield* buildClient(appDirectory, clientOutput);
31496
31539
  const server = yield* buildServer(appDirectory, serverOutput, codegen.functionModules);
31497
31540
  const payloadFiles = yield* readArtifactDirectory(stagingDirectory);
31498
- const inventory = yield* makeDeploymentInventory(payloadFiles, client.routes);
31541
+ const inventory = yield* makeDeploymentInventory(payloadFiles);
31499
31542
  yield* fileSystem.writeFile(path.join(stagingDirectory, deploymentInventoryPath), inventory.bytes);
31500
31543
  const artifactFiles = yield* readArtifactDirectory(stagingDirectory);
31501
31544
  yield* validateDeploymentArtifact(artifactFiles);