@treeseed/sdk 0.13.0-rc.49 → 0.13.0-rc.50

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.
@@ -127,6 +127,25 @@ const packageEndpointSchema = z.object({
127
127
  if (endpoint.visibility === "host" && !endpoint.healthGate) context.addIssue({ code: z.ZodIssueCode.custom, path: ["healthGate"], message: "Host-visible endpoints require a health gate." });
128
128
  if (endpoint.visibility === "private" && endpoint.defaultAlias) context.addIssue({ code: z.ZodIssueCode.custom, path: ["defaultAlias"], message: "Private endpoints cannot declare host aliases." });
129
129
  });
130
+ const environmentName = z.string().regex(/^[A-Z][A-Z0-9_]{0,127}$/u, "Environment names must use portable uppercase identifiers.");
131
+ const componentSecretPath = z.string().regex(/^\/etc\/treeseed\/credentials\/[a-z0-9][a-z0-9._-]{0,127}$/u, "Secret inputs must use manager-owned credential paths.");
132
+ const componentConfigurationPath = z.string().regex(/^\/etc\/treeseed\/components\/[a-z][a-z0-9.-]*\/[a-z0-9][a-z0-9._-]{0,127}$/u, "Configuration inputs must use manager-owned component paths.");
133
+ const componentRuntimeConfigurationSchema = z.object({
134
+ environment: z.array(z.object({ name: environmentName, required: z.boolean(), default: z.string().max(16384).optional() }).strict()).default([]),
135
+ secretEnvironment: z.array(z.object({ name: environmentName, required: z.boolean() }).strict()).default([]),
136
+ secretFiles: z.array(z.object({ id: identifier, path: componentSecretPath, required: z.boolean() }).strict()).default([]),
137
+ files: z.array(z.object({ id: identifier, path: componentConfigurationPath, required: z.boolean(), sensitive: z.boolean().default(false) }).strict()).default([])
138
+ }).strict().default({ environment: [], secretEnvironment: [], secretFiles: [], files: [] }).superRefine((configuration, context) => {
139
+ const environment = configuration.environment.map(({ name }) => name);
140
+ const secretEnvironment = configuration.secretEnvironment.map(({ name }) => name);
141
+ for (const [path, values] of [["environment", environment], ["secretEnvironment", secretEnvironment]]) {
142
+ if (new Set(values).size !== values.length) context.addIssue({ code: z.ZodIssueCode.custom, path: [path], message: `Duplicate ${path} inputs are not allowed.` });
143
+ }
144
+ const overlap = environment.filter((name) => secretEnvironment.includes(name));
145
+ if (overlap.length) context.addIssue({ code: z.ZodIssueCode.custom, path: ["secretEnvironment"], message: `Environment inputs cannot have both public and secret custody: ${overlap.join(", ")}.` });
146
+ const filePaths = [...configuration.secretFiles.map(({ path }) => path), ...configuration.files.map(({ path }) => path)];
147
+ if (new Set(filePaths).size !== filePaths.length) context.addIssue({ code: z.ZodIssueCode.custom, path: ["files"], message: "Component file input paths must be unique." });
148
+ });
130
149
  const packageRuntimeSchema = z.object({
131
150
  schemaVersion: z.literal("treeseed.package-runtime/v1"),
132
151
  componentId: identifier,
@@ -135,6 +154,7 @@ const packageRuntimeSchema = z.object({
135
154
  projectName: identifier,
136
155
  files: z.array(z.object({ path: z.string().min(1), digest }).strict()).min(1)
137
156
  }).strict(),
157
+ configuration: componentRuntimeConfigurationSchema,
138
158
  services: z.array(z.object({ id: identifier, composeService: identifier, endpoints: z.array(packageEndpointSchema) }).strict()).min(1),
139
159
  stateVolumes: z.array(z.object({ id: identifier, volume: z.string().min(1), backup: z.enum(["required", "optional", "none"]) }).strict()),
140
160
  migrations: z.array(z.object({ id: identifier, order: z.number().int().nonnegative(), backupRequired: z.boolean() }).strict()),
@@ -148,6 +168,7 @@ const packageRuntimeSchema = z.object({
148
168
  }).strict().superRefine((runtime, context) => {
149
169
  const endpointIds = runtime.services.flatMap((service) => service.endpoints.map((endpoint) => `${service.id}.${endpoint.id}`));
150
170
  if (new Set(endpointIds).size !== endpointIds.length) context.addIssue({ code: z.ZodIssueCode.custom, path: ["services"], message: "Endpoint identities must be unique within a component." });
171
+ for (const file of runtime.configuration.files) if (!file.path.startsWith(`/etc/treeseed/components/${runtime.componentId}/`)) context.addIssue({ code: z.ZodIssueCode.custom, path: ["configuration", "files"], message: `Configuration file ${file.id} is outside component ${runtime.componentId} custody.` });
151
172
  });
152
173
  const catalogPackageSchema = z.object({ name: z.string().regex(/^treeseed(?:-[a-z0-9-]+)?$/u), version: packageVersion, architecture: z.enum(["amd64", "all"]), origin: z.literal("TreeSeed Deployment"), order: z.number().int().nonnegative() }).strict();
153
174
  const catalogImageSchema = z.object({ role: identifier, repository: ociRepository, digest, platforms: z.array(z.enum(["linux/amd64", "linux/arm64"])).min(1), consumers: z.array(identifier).min(1) }).strict();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.13.0-rc.49",
3
+ "version": "0.13.0-rc.50",
4
4
  "description": "Portable TreeSeed contracts, standards, and typed remote control-plane clients.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {