@savvy-web/silk 1.0.0 → 1.1.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.
@@ -74158,6 +74158,26 @@ const DEFAULT_REGISTRIES = {
74158
74158
  github: "https://npm.pkg.github.com"
74159
74159
  };
74160
74160
  /**
74161
+ * Whether a registry endpoint participates in npm-style SLSA provenance.
74162
+ *
74163
+ * @remarks
74164
+ * The npm public registry and GitHub Packages both accept provenance attestations through the
74165
+ * Sigstore/OIDC trusted-publishing flow, so a {@link PublishTarget} bound to either is marked
74166
+ * `provenance: true` by default — this is what gates the release action's attestation step. JSR
74167
+ * and custom registries do not participate and resolve to `false`. Matching is endpoint-based
74168
+ * (not target-key based) so a custom key pointed at one of these registries still opts in.
74169
+ */
74170
+ const provenanceForRegistry = (registry) => {
74171
+ const normalized = /^[a-z]+:\/\//i.test(registry) ? registry : `https://${registry}`;
74172
+ let hostname;
74173
+ try {
74174
+ hostname = new URL(normalized).hostname.toLowerCase();
74175
+ } catch {
74176
+ return false;
74177
+ }
74178
+ return hostname === "registry.npmjs.org" || hostname === "npm.pkg.github.com";
74179
+ };
74180
+ /**
74161
74181
  * Silk publishability rules over `workspaces-effect`'s {@link PublishTarget}.
74162
74182
  *
74163
74183
  * @remarks
@@ -74199,28 +74219,41 @@ var SilkPublishability = class {
74199
74219
  name: t.name,
74200
74220
  registry: t.registry,
74201
74221
  directory: dirByGroup.get(t.group) ?? `dist/prod/${t.group}/pkg`,
74202
- access
74222
+ access,
74223
+ provenance: provenanceForRegistry(t.registry)
74203
74224
  }));
74204
74225
  }
74205
- return Object.keys(targets).map((id) => new PublishTarget({
74226
+ return Object.entries(targets).map(([id, target]) => {
74227
+ const registry = typeof target === "object" && target !== null && typeof target.registry === "string" ? target.registry : DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT;
74228
+ return new PublishTarget({
74229
+ name: pkgName,
74230
+ registry,
74231
+ directory: `dist/prod/${id}/pkg`,
74232
+ access,
74233
+ provenance: provenanceForRegistry(registry)
74234
+ });
74235
+ });
74236
+ }
74237
+ if (pc && (pc.access === "public" || pc.access === "restricted")) {
74238
+ const registry = pc.registry ?? NPM_DEFAULT;
74239
+ return [new PublishTarget({
74206
74240
  name: pkgName,
74207
- registry: DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT,
74208
- directory: `dist/prod/${id}/pkg`,
74209
- access
74210
- }));
74241
+ registry,
74242
+ directory: pc.directory ?? ".",
74243
+ access: pc.access,
74244
+ provenance: provenanceForRegistry(registry)
74245
+ })];
74246
+ }
74247
+ if (raw.private !== true) {
74248
+ const registry = pc?.registry ?? NPM_DEFAULT;
74249
+ return [new PublishTarget({
74250
+ name: pkgName,
74251
+ registry,
74252
+ directory: pc?.directory ?? ".",
74253
+ access: pc?.access ?? "public",
74254
+ provenance: provenanceForRegistry(registry)
74255
+ })];
74211
74256
  }
74212
- if (pc && (pc.access === "public" || pc.access === "restricted")) return [new PublishTarget({
74213
- name: pkgName,
74214
- registry: pc.registry ?? NPM_DEFAULT,
74215
- directory: pc.directory ?? ".",
74216
- access: pc.access
74217
- })];
74218
- if (raw.private !== true) return [new PublishTarget({
74219
- name: pkgName,
74220
- registry: pc?.registry ?? NPM_DEFAULT,
74221
- directory: pc?.directory ?? ".",
74222
- access: pc?.access ?? "public"
74223
- })];
74224
74257
  return [];
74225
74258
  }
74226
74259
  /**
@@ -77211,10 +77244,12 @@ function readRawPackageJson(fs, pkgDir) {
77211
77244
  /**
77212
77245
  * Build resolved scopes from the discovered workspace packages, keeping only
77213
77246
  * those that are a release surface (declare publishConfig that yields at least
77214
- * one publish target). Used when `.changeset/config.json` declares no explicit
77215
- * `packages` record. The changeset `ignore` list is intentionally NOT consulted
77216
- * here an ignored package still declares publishConfig and remains a valid
77217
- * changeset target.
77247
+ * one publish target). Used both when `.changeset/config.json` declares no
77248
+ * explicit `packages` record AND to augment an explicit record with the
77249
+ * remaining workspace packages it does not list (so the record annotates the
77250
+ * listed packages without shrinking the release surface). The changeset
77251
+ * `ignore` list is intentionally NOT consulted here — an ignored package still
77252
+ * declares publishConfig and remains a valid changeset target.
77218
77253
  */
77219
77254
  function buildFallbackScopes(fs, workspaces) {
77220
77255
  return effect.Effect.forEach(workspaces, (ws) => effect.Effect.gen(function* () {
@@ -77328,19 +77363,24 @@ function makeShape$2(reader, discovery, fs) {
77328
77363
  }));
77329
77364
  const hasExplicitPackages = Object.keys(decodedOptions.packages ?? {}).length > 0;
77330
77365
  let scopes;
77331
- if (hasExplicitPackages) try {
77332
- scopes = buildResolvedScopes({
77333
- options: decodedOptions,
77334
- workspaces,
77335
- projectDir,
77336
- configPath
77337
- });
77338
- checkConflicts(scopes, workspaces, projectDir, configPath);
77339
- } catch (e) {
77340
- if (e instanceof ConfigurationError) return yield* effect.Effect.fail(e);
77341
- throw e;
77342
- }
77343
- else scopes = yield* buildFallbackScopes(fs, workspaces);
77366
+ if (hasExplicitPackages) {
77367
+ let explicitScopes;
77368
+ try {
77369
+ explicitScopes = buildResolvedScopes({
77370
+ options: decodedOptions,
77371
+ workspaces,
77372
+ projectDir,
77373
+ configPath
77374
+ });
77375
+ checkConflicts(explicitScopes, workspaces, projectDir, configPath);
77376
+ } catch (e) {
77377
+ if (e instanceof ConfigurationError) return yield* effect.Effect.fail(e);
77378
+ throw e;
77379
+ }
77380
+ const explicitNames = new Set(explicitScopes.map((s) => s.name));
77381
+ const discoveredScopes = yield* buildFallbackScopes(fs, workspaces.filter((w) => !explicitNames.has(w.name)));
77382
+ scopes = [...explicitScopes, ...discoveredScopes];
77383
+ } else scopes = yield* buildFallbackScopes(fs, workspaces);
77344
77384
  const inspected = {
77345
77385
  configPath,
77346
77386
  projectDir,
@@ -74162,6 +74162,26 @@ const DEFAULT_REGISTRIES = {
74162
74162
  github: "https://npm.pkg.github.com"
74163
74163
  };
74164
74164
  /**
74165
+ * Whether a registry endpoint participates in npm-style SLSA provenance.
74166
+ *
74167
+ * @remarks
74168
+ * The npm public registry and GitHub Packages both accept provenance attestations through the
74169
+ * Sigstore/OIDC trusted-publishing flow, so a {@link PublishTarget} bound to either is marked
74170
+ * `provenance: true` by default — this is what gates the release action's attestation step. JSR
74171
+ * and custom registries do not participate and resolve to `false`. Matching is endpoint-based
74172
+ * (not target-key based) so a custom key pointed at one of these registries still opts in.
74173
+ */
74174
+ const provenanceForRegistry = (registry) => {
74175
+ const normalized = /^[a-z]+:\/\//i.test(registry) ? registry : `https://${registry}`;
74176
+ let hostname;
74177
+ try {
74178
+ hostname = new URL(normalized).hostname.toLowerCase();
74179
+ } catch {
74180
+ return false;
74181
+ }
74182
+ return hostname === "registry.npmjs.org" || hostname === "npm.pkg.github.com";
74183
+ };
74184
+ /**
74165
74185
  * Silk publishability rules over `workspaces-effect`'s {@link PublishTarget}.
74166
74186
  *
74167
74187
  * @remarks
@@ -74203,28 +74223,41 @@ var SilkPublishability = class {
74203
74223
  name: t.name,
74204
74224
  registry: t.registry,
74205
74225
  directory: dirByGroup.get(t.group) ?? `dist/prod/${t.group}/pkg`,
74206
- access
74226
+ access,
74227
+ provenance: provenanceForRegistry(t.registry)
74207
74228
  }));
74208
74229
  }
74209
- return Object.keys(targets).map((id) => new PublishTarget({
74230
+ return Object.entries(targets).map(([id, target]) => {
74231
+ const registry = typeof target === "object" && target !== null && typeof target.registry === "string" ? target.registry : DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT;
74232
+ return new PublishTarget({
74233
+ name: pkgName,
74234
+ registry,
74235
+ directory: `dist/prod/${id}/pkg`,
74236
+ access,
74237
+ provenance: provenanceForRegistry(registry)
74238
+ });
74239
+ });
74240
+ }
74241
+ if (pc && (pc.access === "public" || pc.access === "restricted")) {
74242
+ const registry = pc.registry ?? NPM_DEFAULT;
74243
+ return [new PublishTarget({
74210
74244
  name: pkgName,
74211
- registry: DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT,
74212
- directory: `dist/prod/${id}/pkg`,
74213
- access
74214
- }));
74245
+ registry,
74246
+ directory: pc.directory ?? ".",
74247
+ access: pc.access,
74248
+ provenance: provenanceForRegistry(registry)
74249
+ })];
74250
+ }
74251
+ if (raw.private !== true) {
74252
+ const registry = pc?.registry ?? NPM_DEFAULT;
74253
+ return [new PublishTarget({
74254
+ name: pkgName,
74255
+ registry,
74256
+ directory: pc?.directory ?? ".",
74257
+ access: pc?.access ?? "public",
74258
+ provenance: provenanceForRegistry(registry)
74259
+ })];
74215
74260
  }
74216
- if (pc && (pc.access === "public" || pc.access === "restricted")) return [new PublishTarget({
74217
- name: pkgName,
74218
- registry: pc.registry ?? NPM_DEFAULT,
74219
- directory: pc.directory ?? ".",
74220
- access: pc.access
74221
- })];
74222
- if (raw.private !== true) return [new PublishTarget({
74223
- name: pkgName,
74224
- registry: pc?.registry ?? NPM_DEFAULT,
74225
- directory: pc?.directory ?? ".",
74226
- access: pc?.access ?? "public"
74227
- })];
74228
74261
  return [];
74229
74262
  }
74230
74263
  /**
@@ -77215,10 +77248,12 @@ function readRawPackageJson(fs, pkgDir) {
77215
77248
  /**
77216
77249
  * Build resolved scopes from the discovered workspace packages, keeping only
77217
77250
  * those that are a release surface (declare publishConfig that yields at least
77218
- * one publish target). Used when `.changeset/config.json` declares no explicit
77219
- * `packages` record. The changeset `ignore` list is intentionally NOT consulted
77220
- * here an ignored package still declares publishConfig and remains a valid
77221
- * changeset target.
77251
+ * one publish target). Used both when `.changeset/config.json` declares no
77252
+ * explicit `packages` record AND to augment an explicit record with the
77253
+ * remaining workspace packages it does not list (so the record annotates the
77254
+ * listed packages without shrinking the release surface). The changeset
77255
+ * `ignore` list is intentionally NOT consulted here — an ignored package still
77256
+ * declares publishConfig and remains a valid changeset target.
77222
77257
  */
77223
77258
  function buildFallbackScopes(fs, workspaces) {
77224
77259
  return effect.Effect.forEach(workspaces, (ws) => effect.Effect.gen(function* () {
@@ -77332,19 +77367,24 @@ function makeShape$2(reader, discovery, fs) {
77332
77367
  }));
77333
77368
  const hasExplicitPackages = Object.keys(decodedOptions.packages ?? {}).length > 0;
77334
77369
  let scopes;
77335
- if (hasExplicitPackages) try {
77336
- scopes = buildResolvedScopes({
77337
- options: decodedOptions,
77338
- workspaces,
77339
- projectDir,
77340
- configPath
77341
- });
77342
- checkConflicts(scopes, workspaces, projectDir, configPath);
77343
- } catch (e) {
77344
- if (e instanceof ConfigurationError) return yield* effect.Effect.fail(e);
77345
- throw e;
77346
- }
77347
- else scopes = yield* buildFallbackScopes(fs, workspaces);
77370
+ if (hasExplicitPackages) {
77371
+ let explicitScopes;
77372
+ try {
77373
+ explicitScopes = buildResolvedScopes({
77374
+ options: decodedOptions,
77375
+ workspaces,
77376
+ projectDir,
77377
+ configPath
77378
+ });
77379
+ checkConflicts(explicitScopes, workspaces, projectDir, configPath);
77380
+ } catch (e) {
77381
+ if (e instanceof ConfigurationError) return yield* effect.Effect.fail(e);
77382
+ throw e;
77383
+ }
77384
+ const explicitNames = new Set(explicitScopes.map((s) => s.name));
77385
+ const discoveredScopes = yield* buildFallbackScopes(fs, workspaces.filter((w) => !explicitNames.has(w.name)));
77386
+ scopes = [...explicitScopes, ...discoveredScopes];
77387
+ } else scopes = yield* buildFallbackScopes(fs, workspaces);
77348
77388
  const inspected = {
77349
77389
  configPath,
77350
77390
  projectDir,
package/lint.d.ts CHANGED
@@ -88,7 +88,9 @@ declare const MARKDOWNLINT_CONFIG: {
88
88
  readonly MD024: {
89
89
  readonly siblings_only: true;
90
90
  };
91
- readonly MD025: true;
91
+ readonly MD025: {
92
+ readonly front_matter_title: "";
93
+ };
92
94
  readonly MD026: true;
93
95
  readonly MD027: true;
94
96
  readonly MD028: true;
@@ -141,7 +143,7 @@ declare const MARKDOWNLINT_TEMPLATE: {
141
143
  readonly fix: true;
142
144
  readonly gitignore: true;
143
145
  readonly noBanner: true;
144
- readonly ignores: readonly ["**/node_modules", "**/.cache", "**/coverage", "**/.coverage", "**/dist", "**/CHANGELOG.md", "**/.claude/plans", "**/docs/superpowers"];
146
+ readonly ignores: readonly ["**/node_modules", "**/.cache", "**/coverage", "**/.coverage", "**/dist", "**/CHANGELOG.md", "**/.claude/plans", "**/docs/superpowers", "**/__test__/**/fixtures/**", "**/__fixtures__/**"];
145
147
  readonly customRules: readonly ["@savvy-web/silk/changesets/markdownlint"];
146
148
  readonly config: {
147
149
  readonly default: true;
@@ -171,7 +173,9 @@ declare const MARKDOWNLINT_TEMPLATE: {
171
173
  readonly MD024: {
172
174
  readonly siblings_only: true;
173
175
  };
174
- readonly MD025: true;
176
+ readonly MD025: {
177
+ readonly front_matter_title: "";
178
+ };
175
179
  readonly MD026: true;
176
180
  readonly MD027: true;
177
181
  readonly MD028: true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/silk",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "private": false,
5
5
  "description": "The single Silk Suite dev-tooling package — changeset, commitlint, lint, and biome conventions",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk",
@@ -60,11 +60,13 @@
60
60
  "import": "./lint.js"
61
61
  },
62
62
  "./biome": "./public/biome/silk.jsonc",
63
+ "./tsconfig/node/root.json": "./public/tsconfig/node/root.json",
64
+ "./tsconfig/rspress/website.json": "./public/tsconfig/rspress/website.json",
63
65
  "./package.json": "./package.json"
64
66
  },
65
67
  "dependencies": {
66
68
  "@effect/platform": "^0.96.1",
67
- "@savvy-web/silk-effects": "1.1.0",
69
+ "@savvy-web/silk-effects": "1.3.0",
68
70
  "effect": "^3.21.3",
69
71
  "semver": "^7.8.4"
70
72
  },
@@ -73,8 +75,8 @@
73
75
  "@changesets/cli": "^2.31.0",
74
76
  "@commitlint/cli": "^21.0.1",
75
77
  "@commitlint/config-conventional": "^21.0.2",
76
- "@savvy-web/cli": "1.0.0",
77
- "@savvy-web/mcp": "1.0.0",
78
+ "@savvy-web/cli": "1.1.1",
79
+ "@savvy-web/mcp": "1.1.1",
78
80
  "@types/node": "^25.9.0",
79
81
  "@typescript/native-preview": "^7.0.0-dev.20260513.1",
80
82
  "commitizen": "^4.3.0",
@@ -248,10 +248,12 @@ function readRawPackageJson(fs, pkgDir) {
248
248
  /**
249
249
  * Build resolved scopes from the discovered workspace packages, keeping only
250
250
  * those that are a release surface (declare publishConfig that yields at least
251
- * one publish target). Used when `.changeset/config.json` declares no explicit
252
- * `packages` record. The changeset `ignore` list is intentionally NOT consulted
253
- * here an ignored package still declares publishConfig and remains a valid
254
- * changeset target.
251
+ * one publish target). Used both when `.changeset/config.json` declares no
252
+ * explicit `packages` record AND to augment an explicit record with the
253
+ * remaining workspace packages it does not list (so the record annotates the
254
+ * listed packages without shrinking the release surface). The changeset
255
+ * `ignore` list is intentionally NOT consulted here — an ignored package still
256
+ * declares publishConfig and remains a valid changeset target.
255
257
  */
256
258
  function buildFallbackScopes(fs, workspaces) {
257
259
  return effect.Effect.forEach(workspaces, (ws) => effect.Effect.gen(function* () {
@@ -365,19 +367,24 @@ function makeShape(reader, discovery, fs) {
365
367
  }));
366
368
  const hasExplicitPackages = Object.keys(decodedOptions.packages ?? {}).length > 0;
367
369
  let scopes;
368
- if (hasExplicitPackages) try {
369
- scopes = buildResolvedScopes({
370
- options: decodedOptions,
371
- workspaces,
372
- projectDir,
373
- configPath
374
- });
375
- checkConflicts(scopes, workspaces, projectDir, configPath);
376
- } catch (e) {
377
- if (e instanceof require_errors.ConfigurationError) return yield* effect.Effect.fail(e);
378
- throw e;
379
- }
380
- else scopes = yield* buildFallbackScopes(fs, workspaces);
370
+ if (hasExplicitPackages) {
371
+ let explicitScopes;
372
+ try {
373
+ explicitScopes = buildResolvedScopes({
374
+ options: decodedOptions,
375
+ workspaces,
376
+ projectDir,
377
+ configPath
378
+ });
379
+ checkConflicts(explicitScopes, workspaces, projectDir, configPath);
380
+ } catch (e) {
381
+ if (e instanceof require_errors.ConfigurationError) return yield* effect.Effect.fail(e);
382
+ throw e;
383
+ }
384
+ const explicitNames = new Set(explicitScopes.map((s) => s.name));
385
+ const discoveredScopes = yield* buildFallbackScopes(fs, workspaces.filter((w) => !explicitNames.has(w.name)));
386
+ scopes = [...explicitScopes, ...discoveredScopes];
387
+ } else scopes = yield* buildFallbackScopes(fs, workspaces);
381
388
  const inspected = {
382
389
  configPath,
383
390
  projectDir,
@@ -248,10 +248,12 @@ function readRawPackageJson(fs, pkgDir) {
248
248
  /**
249
249
  * Build resolved scopes from the discovered workspace packages, keeping only
250
250
  * those that are a release surface (declare publishConfig that yields at least
251
- * one publish target). Used when `.changeset/config.json` declares no explicit
252
- * `packages` record. The changeset `ignore` list is intentionally NOT consulted
253
- * here an ignored package still declares publishConfig and remains a valid
254
- * changeset target.
251
+ * one publish target). Used both when `.changeset/config.json` declares no
252
+ * explicit `packages` record AND to augment an explicit record with the
253
+ * remaining workspace packages it does not list (so the record annotates the
254
+ * listed packages without shrinking the release surface). The changeset
255
+ * `ignore` list is intentionally NOT consulted here — an ignored package still
256
+ * declares publishConfig and remains a valid changeset target.
255
257
  */
256
258
  function buildFallbackScopes(fs, workspaces) {
257
259
  return Effect.forEach(workspaces, (ws) => Effect.gen(function* () {
@@ -365,19 +367,24 @@ function makeShape(reader, discovery, fs) {
365
367
  }));
366
368
  const hasExplicitPackages = Object.keys(decodedOptions.packages ?? {}).length > 0;
367
369
  let scopes;
368
- if (hasExplicitPackages) try {
369
- scopes = buildResolvedScopes({
370
- options: decodedOptions,
371
- workspaces,
372
- projectDir,
373
- configPath
374
- });
375
- checkConflicts(scopes, workspaces, projectDir, configPath);
376
- } catch (e) {
377
- if (e instanceof ConfigurationError) return yield* Effect.fail(e);
378
- throw e;
379
- }
380
- else scopes = yield* buildFallbackScopes(fs, workspaces);
370
+ if (hasExplicitPackages) {
371
+ let explicitScopes;
372
+ try {
373
+ explicitScopes = buildResolvedScopes({
374
+ options: decodedOptions,
375
+ workspaces,
376
+ projectDir,
377
+ configPath
378
+ });
379
+ checkConflicts(explicitScopes, workspaces, projectDir, configPath);
380
+ } catch (e) {
381
+ if (e instanceof ConfigurationError) return yield* Effect.fail(e);
382
+ throw e;
383
+ }
384
+ const explicitNames = new Set(explicitScopes.map((s) => s.name));
385
+ const discoveredScopes = yield* buildFallbackScopes(fs, workspaces.filter((w) => !explicitNames.has(w.name)));
386
+ scopes = [...explicitScopes, ...discoveredScopes];
387
+ } else scopes = yield* buildFallbackScopes(fs, workspaces);
381
388
  const inspected = {
382
389
  configPath,
383
390
  projectDir,
@@ -16,6 +16,26 @@ const DEFAULT_REGISTRIES = {
16
16
  github: "https://npm.pkg.github.com"
17
17
  };
18
18
  /**
19
+ * Whether a registry endpoint participates in npm-style SLSA provenance.
20
+ *
21
+ * @remarks
22
+ * The npm public registry and GitHub Packages both accept provenance attestations through the
23
+ * Sigstore/OIDC trusted-publishing flow, so a {@link PublishTarget} bound to either is marked
24
+ * `provenance: true` by default — this is what gates the release action's attestation step. JSR
25
+ * and custom registries do not participate and resolve to `false`. Matching is endpoint-based
26
+ * (not target-key based) so a custom key pointed at one of these registries still opts in.
27
+ */
28
+ const provenanceForRegistry = (registry) => {
29
+ const normalized = /^[a-z]+:\/\//i.test(registry) ? registry : `https://${registry}`;
30
+ let hostname;
31
+ try {
32
+ hostname = new URL(normalized).hostname.toLowerCase();
33
+ } catch {
34
+ return false;
35
+ }
36
+ return hostname === "registry.npmjs.org" || hostname === "npm.pkg.github.com";
37
+ };
38
+ /**
19
39
  * Silk publishability rules over `workspaces-effect`'s {@link PublishTarget}.
20
40
  *
21
41
  * @remarks
@@ -57,28 +77,41 @@ var SilkPublishability = class {
57
77
  name: t.name,
58
78
  registry: t.registry,
59
79
  directory: dirByGroup.get(t.group) ?? `dist/prod/${t.group}/pkg`,
60
- access
80
+ access,
81
+ provenance: provenanceForRegistry(t.registry)
61
82
  }));
62
83
  }
63
- return Object.keys(targets).map((id) => new require_index.PublishTarget({
84
+ return Object.entries(targets).map(([id, target]) => {
85
+ const registry = typeof target === "object" && target !== null && typeof target.registry === "string" ? target.registry : DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT;
86
+ return new require_index.PublishTarget({
87
+ name: pkgName,
88
+ registry,
89
+ directory: `dist/prod/${id}/pkg`,
90
+ access,
91
+ provenance: provenanceForRegistry(registry)
92
+ });
93
+ });
94
+ }
95
+ if (pc && (pc.access === "public" || pc.access === "restricted")) {
96
+ const registry = pc.registry ?? NPM_DEFAULT;
97
+ return [new require_index.PublishTarget({
98
+ name: pkgName,
99
+ registry,
100
+ directory: pc.directory ?? ".",
101
+ access: pc.access,
102
+ provenance: provenanceForRegistry(registry)
103
+ })];
104
+ }
105
+ if (raw.private !== true) {
106
+ const registry = pc?.registry ?? NPM_DEFAULT;
107
+ return [new require_index.PublishTarget({
64
108
  name: pkgName,
65
- registry: DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT,
66
- directory: `dist/prod/${id}/pkg`,
67
- access
68
- }));
109
+ registry,
110
+ directory: pc?.directory ?? ".",
111
+ access: pc?.access ?? "public",
112
+ provenance: provenanceForRegistry(registry)
113
+ })];
69
114
  }
70
- if (pc && (pc.access === "public" || pc.access === "restricted")) return [new require_index.PublishTarget({
71
- name: pkgName,
72
- registry: pc.registry ?? NPM_DEFAULT,
73
- directory: pc.directory ?? ".",
74
- access: pc.access
75
- })];
76
- if (raw.private !== true) return [new require_index.PublishTarget({
77
- name: pkgName,
78
- registry: pc?.registry ?? NPM_DEFAULT,
79
- directory: pc?.directory ?? ".",
80
- access: pc?.access ?? "public"
81
- })];
82
115
  return [];
83
116
  }
84
117
  /**
@@ -16,6 +16,26 @@ const DEFAULT_REGISTRIES = {
16
16
  github: "https://npm.pkg.github.com"
17
17
  };
18
18
  /**
19
+ * Whether a registry endpoint participates in npm-style SLSA provenance.
20
+ *
21
+ * @remarks
22
+ * The npm public registry and GitHub Packages both accept provenance attestations through the
23
+ * Sigstore/OIDC trusted-publishing flow, so a {@link PublishTarget} bound to either is marked
24
+ * `provenance: true` by default — this is what gates the release action's attestation step. JSR
25
+ * and custom registries do not participate and resolve to `false`. Matching is endpoint-based
26
+ * (not target-key based) so a custom key pointed at one of these registries still opts in.
27
+ */
28
+ const provenanceForRegistry = (registry) => {
29
+ const normalized = /^[a-z]+:\/\//i.test(registry) ? registry : `https://${registry}`;
30
+ let hostname;
31
+ try {
32
+ hostname = new URL(normalized).hostname.toLowerCase();
33
+ } catch {
34
+ return false;
35
+ }
36
+ return hostname === "registry.npmjs.org" || hostname === "npm.pkg.github.com";
37
+ };
38
+ /**
19
39
  * Silk publishability rules over `workspaces-effect`'s {@link PublishTarget}.
20
40
  *
21
41
  * @remarks
@@ -57,28 +77,41 @@ var SilkPublishability = class {
57
77
  name: t.name,
58
78
  registry: t.registry,
59
79
  directory: dirByGroup.get(t.group) ?? `dist/prod/${t.group}/pkg`,
60
- access
80
+ access,
81
+ provenance: provenanceForRegistry(t.registry)
61
82
  }));
62
83
  }
63
- return Object.keys(targets).map((id) => new PublishTarget({
84
+ return Object.entries(targets).map(([id, target]) => {
85
+ const registry = typeof target === "object" && target !== null && typeof target.registry === "string" ? target.registry : DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT;
86
+ return new PublishTarget({
87
+ name: pkgName,
88
+ registry,
89
+ directory: `dist/prod/${id}/pkg`,
90
+ access,
91
+ provenance: provenanceForRegistry(registry)
92
+ });
93
+ });
94
+ }
95
+ if (pc && (pc.access === "public" || pc.access === "restricted")) {
96
+ const registry = pc.registry ?? NPM_DEFAULT;
97
+ return [new PublishTarget({
98
+ name: pkgName,
99
+ registry,
100
+ directory: pc.directory ?? ".",
101
+ access: pc.access,
102
+ provenance: provenanceForRegistry(registry)
103
+ })];
104
+ }
105
+ if (raw.private !== true) {
106
+ const registry = pc?.registry ?? NPM_DEFAULT;
107
+ return [new PublishTarget({
64
108
  name: pkgName,
65
- registry: DEFAULT_REGISTRIES[id] ?? pc?.registry ?? NPM_DEFAULT,
66
- directory: `dist/prod/${id}/pkg`,
67
- access
68
- }));
109
+ registry,
110
+ directory: pc?.directory ?? ".",
111
+ access: pc?.access ?? "public",
112
+ provenance: provenanceForRegistry(registry)
113
+ })];
69
114
  }
70
- if (pc && (pc.access === "public" || pc.access === "restricted")) return [new PublishTarget({
71
- name: pkgName,
72
- registry: pc.registry ?? NPM_DEFAULT,
73
- directory: pc.directory ?? ".",
74
- access: pc.access
75
- })];
76
- if (raw.private !== true) return [new PublishTarget({
77
- name: pkgName,
78
- registry: pc?.registry ?? NPM_DEFAULT,
79
- directory: pc?.directory ?? ".",
80
- access: pc?.access ?? "public"
81
- })];
82
115
  return [];
83
116
  }
84
117
  /**
@@ -107,7 +107,7 @@
107
107
  }
108
108
  }
109
109
  },
110
- "includes": ["**/turbo.json", "**/tsconfig.json", "**/tsconfig.*.json"]
110
+ "includes": ["**/turbo.json", "**/tsconfig.json", "**/tsconfig.*.json", "**/public/tsconfig/**/*.json"]
111
111
  },
112
112
  {
113
113
  "includes": ["**/*.test.ts"],
@@ -138,7 +138,8 @@
138
138
  "!**/.vitest",
139
139
  "!**/.coverage",
140
140
  "!coverage",
141
- "!**/__test__/fixtures",
141
+ "!.claude/worktrees",
142
+ "!**/__test__/**/fixtures",
142
143
  "!**/__test__/snapshots",
143
144
  "!**/__test__/**/fixtures",
144
145
  "!**/__test__/**/snapshots",
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "composite": true,
5
+ "declaration": true,
6
+ "module": "nodenext",
7
+ "outDir": "dist",
8
+ "resolveJsonModule": true,
9
+ "strict": true,
10
+ "strictNullChecks": true,
11
+ "target": "es2025",
12
+ "types": ["node"]
13
+ },
14
+ "exclude": ["${configDir}/node_modules", "${configDir}/dist/**/*"],
15
+ "include": [
16
+ "${configDir}/types/*.ts",
17
+ "${configDir}/package.json",
18
+ "${configDir}/*.ts",
19
+ "${configDir}/*.cts",
20
+ "${configDir}/*.mts",
21
+ "${configDir}/src/**/*.ts",
22
+ "${configDir}/src/**/*.tsx",
23
+ "${configDir}/src/**/*.cts",
24
+ "${configDir}/src/**/*.mts",
25
+ "${configDir}/lib/**/*.ts",
26
+ "${configDir}/lib/**/*.tsx",
27
+ "${configDir}/lib/**/*.cts",
28
+ "${configDir}/lib/**/*.mts",
29
+ "${configDir}/__test__/**/*.ts",
30
+ "${configDir}/__test__/**/*.tsx",
31
+ "${configDir}/__test__/**/*.cts",
32
+ "${configDir}/__test__/**/*.mts",
33
+ "${configDir}/public/**/*.json"
34
+ ]
35
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig.json",
3
+ "compilerOptions": {
4
+ "allowImportingTsExtensions": true,
5
+ "isolatedModules": true,
6
+ "jsx": "react-jsx",
7
+ "lib": ["dom", "es2023"],
8
+ "module": "esnext",
9
+ "moduleDetection": "force",
10
+ "moduleResolution": "bundler",
11
+ "noEmit": true,
12
+ "noUncheckedSideEffectImports": true,
13
+ "noUnusedLocals": true,
14
+ "noUnusedParameters": true,
15
+ "resolveJsonModule": true,
16
+ "skipLibCheck": true,
17
+ "strict": true,
18
+ "target": "es2023",
19
+ "types": ["node", "react", "react-dom"],
20
+ "useDefineForClassFields": true,
21
+ "verbatimModuleSyntax": true
22
+ },
23
+ "exclude": ["${configDir}/node_modules", "${configDir}/dist", "${configDir}/.rspress"],
24
+ "include": ["${configDir}/docs", "${configDir}/theme", "${configDir}/rspress.config.ts", "${configDir}/types/*.d.ts"],
25
+ "mdx": {
26
+ "checkMdx": true
27
+ }
28
+ }