@kindgi/cli 0.1.6 → 0.1.7

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 (227) hide show
  1. package/README.md +35 -24
  2. package/dist/commands/auth.d.ts.map +1 -1
  3. package/dist/commands/auth.js +5 -4
  4. package/dist/commands/auth.js.map +1 -1
  5. package/dist/commands/dev.d.ts.map +1 -1
  6. package/dist/commands/dev.js +84 -13
  7. package/dist/commands/dev.js.map +1 -1
  8. package/dist/commands/doctor.d.ts +5 -1
  9. package/dist/commands/doctor.d.ts.map +1 -1
  10. package/dist/commands/doctor.js +104 -19
  11. package/dist/commands/doctor.js.map +1 -1
  12. package/dist/commands/guardrails.d.ts.map +1 -1
  13. package/dist/commands/guardrails.js +13 -2
  14. package/dist/commands/guardrails.js.map +1 -1
  15. package/dist/commands/index.d.ts.map +1 -1
  16. package/dist/commands/index.js +4 -0
  17. package/dist/commands/index.js.map +1 -1
  18. package/dist/commands/init.d.ts +1 -1
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +23 -3
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/license.d.ts +3 -0
  23. package/dist/commands/license.d.ts.map +1 -0
  24. package/dist/commands/license.js +187 -0
  25. package/dist/commands/license.js.map +1 -0
  26. package/dist/commands/mcp.js +1 -1
  27. package/dist/commands/providers.d.ts.map +1 -1
  28. package/dist/commands/providers.js +11 -9
  29. package/dist/commands/providers.js.map +1 -1
  30. package/dist/commands/test.d.ts.map +1 -1
  31. package/dist/commands/test.js +21 -9
  32. package/dist/commands/test.js.map +1 -1
  33. package/dist/commands/webhooks.d.ts +20 -0
  34. package/dist/commands/webhooks.d.ts.map +1 -0
  35. package/dist/commands/webhooks.js +444 -0
  36. package/dist/commands/webhooks.js.map +1 -0
  37. package/dist/context.d.ts +4 -0
  38. package/dist/context.d.ts.map +1 -1
  39. package/dist/context.js +1 -0
  40. package/dist/context.js.map +1 -1
  41. package/dist/dev/already-running.d.ts +22 -0
  42. package/dist/dev/already-running.d.ts.map +1 -0
  43. package/dist/dev/already-running.js +72 -0
  44. package/dist/dev/already-running.js.map +1 -0
  45. package/dist/dev/defaults.d.ts.map +1 -1
  46. package/dist/dev/defaults.js +5 -2
  47. package/dist/dev/defaults.js.map +1 -1
  48. package/dist/dev/dev-lock.d.ts +50 -0
  49. package/dist/dev/dev-lock.d.ts.map +1 -0
  50. package/dist/dev/dev-lock.js +203 -0
  51. package/dist/dev/dev-lock.js.map +1 -0
  52. package/dist/dev/port.d.ts +6 -2
  53. package/dist/dev/port.d.ts.map +1 -1
  54. package/dist/dev/port.js +8 -4
  55. package/dist/dev/port.js.map +1 -1
  56. package/dist/dev/providers.d.ts.map +1 -1
  57. package/dist/dev/providers.js +112 -23
  58. package/dist/dev/providers.js.map +1 -1
  59. package/dist/dev/runners.d.ts +21 -2
  60. package/dist/dev/runners.d.ts.map +1 -1
  61. package/dist/dev/runtime-container.d.ts +78 -3
  62. package/dist/dev/runtime-container.d.ts.map +1 -1
  63. package/dist/dev/runtime-container.js +258 -26
  64. package/dist/dev/runtime-container.js.map +1 -1
  65. package/dist/dev/runtime-image.d.ts +4 -3
  66. package/dist/dev/runtime-image.d.ts.map +1 -1
  67. package/dist/dev/runtime-image.js +4 -3
  68. package/dist/dev/runtime-image.js.map +1 -1
  69. package/dist/dev/runtime-registry.d.ts +0 -9
  70. package/dist/dev/runtime-registry.d.ts.map +1 -1
  71. package/dist/dev/runtime-registry.js +12 -2
  72. package/dist/dev/runtime-registry.js.map +1 -1
  73. package/dist/dev/start-phases.d.ts +41 -0
  74. package/dist/dev/start-phases.d.ts.map +1 -0
  75. package/dist/dev/start-phases.js +103 -0
  76. package/dist/dev/start-phases.js.map +1 -0
  77. package/dist/init/augment-scaffolder.d.ts +20 -7
  78. package/dist/init/augment-scaffolder.d.ts.map +1 -1
  79. package/dist/init/augment-scaffolder.js +94 -21
  80. package/dist/init/augment-scaffolder.js.map +1 -1
  81. package/dist/init/pinning.d.ts +39 -0
  82. package/dist/init/pinning.d.ts.map +1 -0
  83. package/dist/init/pinning.js +130 -0
  84. package/dist/init/pinning.js.map +1 -0
  85. package/dist/init/template-files.d.ts +1 -1
  86. package/dist/init/tsconfig-paths.d.ts +29 -0
  87. package/dist/init/tsconfig-paths.d.ts.map +1 -0
  88. package/dist/init/tsconfig-paths.js +235 -0
  89. package/dist/init/tsconfig-paths.js.map +1 -0
  90. package/dist/init/vitest-setup.d.ts +41 -0
  91. package/dist/init/vitest-setup.d.ts.map +1 -0
  92. package/dist/init/vitest-setup.js +163 -0
  93. package/dist/init/vitest-setup.js.map +1 -0
  94. package/dist/license/aws.d.ts +24 -0
  95. package/dist/license/aws.d.ts.map +1 -0
  96. package/dist/license/aws.js +291 -0
  97. package/dist/license/aws.js.map +1 -0
  98. package/dist/license/cloud.d.ts +13 -0
  99. package/dist/license/cloud.d.ts.map +1 -0
  100. package/dist/license/cloud.js +193 -0
  101. package/dist/license/cloud.js.map +1 -0
  102. package/dist/license/expiry.d.ts +33 -0
  103. package/dist/license/expiry.d.ts.map +1 -0
  104. package/dist/license/expiry.js +35 -0
  105. package/dist/license/expiry.js.map +1 -0
  106. package/dist/license/license-key.d.ts +32 -0
  107. package/dist/license/license-key.d.ts.map +1 -0
  108. package/dist/license/license-key.js +91 -0
  109. package/dist/license/license-key.js.map +1 -0
  110. package/dist/license/protocol.d.ts +63 -0
  111. package/dist/license/protocol.d.ts.map +1 -0
  112. package/dist/license/protocol.js +102 -0
  113. package/dist/license/protocol.js.map +1 -0
  114. package/dist/license/renew.d.ts +59 -0
  115. package/dist/license/renew.d.ts.map +1 -0
  116. package/dist/license/renew.js +153 -0
  117. package/dist/license/renew.js.map +1 -0
  118. package/dist/license/stores.d.ts +19 -0
  119. package/dist/license/stores.d.ts.map +1 -0
  120. package/dist/license/stores.js +150 -0
  121. package/dist/license/stores.js.map +1 -0
  122. package/dist/main.d.ts +3 -0
  123. package/dist/main.d.ts.map +1 -1
  124. package/dist/main.js +1 -0
  125. package/dist/main.js.map +1 -1
  126. package/dist/package-manager.d.ts.map +1 -1
  127. package/dist/package-manager.js +2 -1
  128. package/dist/package-manager.js.map +1 -1
  129. package/dist/providers/preset-loader.d.ts +52 -1
  130. package/dist/providers/preset-loader.d.ts.map +1 -1
  131. package/dist/providers/preset-loader.js +85 -6
  132. package/dist/providers/preset-loader.js.map +1 -1
  133. package/dist/providers/presets/anthropic.json +1 -1
  134. package/dist/providers/presets/azure-openai.json +65 -0
  135. package/dist/providers/presets/bedrock.json +102 -0
  136. package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +3 -3
  137. package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +3 -3
  138. package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +11 -10
  139. package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +4 -4
  140. package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +16 -9
  141. package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +9 -11
  142. package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +3 -3
  143. package/dist/sdk-skills/kindgi-getting-started/SKILL.md +28 -5
  144. package/dist/sdk-skills/kindgi-java-authoring-agents/SKILL.md +1 -1
  145. package/dist/sdk-skills/kindgi-java-authoring-flows/SKILL.md +1 -1
  146. package/dist/sdk-skills/kindgi-java-authoring-guardrails/SKILL.md +1 -1
  147. package/dist/sdk-skills/kindgi-java-authoring-tools/SKILL.md +1 -1
  148. package/dist/sdk-skills/kindgi-java-getting-started/SKILL.md +6 -1
  149. package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +1 -1
  150. package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +1 -1
  151. package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +1 -1
  152. package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +1 -1
  153. package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +6 -1
  154. package/dist/sdk-skills/kindgi-scala-authoring-agents/SKILL.md +1 -1
  155. package/dist/sdk-skills/kindgi-scala-authoring-flows/SKILL.md +1 -1
  156. package/dist/sdk-skills/kindgi-scala-authoring-guardrails/SKILL.md +1 -1
  157. package/dist/sdk-skills/kindgi-scala-authoring-tools/SKILL.md +1 -1
  158. package/dist/sdk-skills/kindgi-scala-getting-started/SKILL.md +6 -1
  159. package/dist/sdk-skills/kindgi-using/SKILL.md +236 -0
  160. package/dist/templates/drupal/.nvmrc +1 -0
  161. package/dist/templates/drupal/AGENTS.md +62 -0
  162. package/dist/templates/drupal/README.md.tmpl +321 -0
  163. package/dist/templates/drupal/agents/content-agent/index.test.ts.tmpl +47 -0
  164. package/dist/templates/drupal/agents/content-agent/index.ts.tmpl +69 -0
  165. package/dist/templates/drupal/agents/content-reviewer/index.test.ts.tmpl +37 -0
  166. package/dist/templates/drupal/agents/content-reviewer/index.ts.tmpl +57 -0
  167. package/dist/templates/drupal/fixtures/node-updated.json +174 -0
  168. package/dist/templates/drupal/flows/content-review/index.ts.tmpl +66 -0
  169. package/dist/templates/drupal/gitignore +8 -0
  170. package/dist/templates/drupal/guardrails/no-contact-details/index.test.ts.tmpl +29 -0
  171. package/dist/templates/drupal/guardrails/no-contact-details/index.ts.tmpl +73 -0
  172. package/dist/templates/drupal/kindgi.config.ts.tmpl +41 -0
  173. package/dist/templates/drupal/lib/drupal.ts.tmpl +64 -0
  174. package/dist/templates/drupal/package.json.tmpl +31 -0
  175. package/dist/templates/drupal/pnpm-workspace.yaml +9 -0
  176. package/dist/templates/drupal/scripts/connect-drupal.mjs.tmpl +57 -0
  177. package/dist/templates/drupal/tools/check-content-event/index.test.ts.tmpl +72 -0
  178. package/dist/templates/drupal/tools/check-content-event/index.ts.tmpl +115 -0
  179. package/dist/templates/drupal/tsconfig.json.tmpl +28 -0
  180. package/dist/templates/drupal/vitest.config.ts.tmpl +14 -0
  181. package/dist/templates/java/AGENTS.md +6 -0
  182. package/dist/templates/java/README.md.tmpl +1 -1
  183. package/dist/templates/minimal/AGENTS.md +6 -0
  184. package/dist/templates/minimal/README.md.tmpl +3 -2
  185. package/dist/templates/minimal/package.json.tmpl +3 -2
  186. package/dist/templates/python/AGENTS.md +3 -2
  187. package/dist/templates/sample/AGENTS.md +6 -0
  188. package/dist/templates/sample/package.json.tmpl +3 -2
  189. package/dist/templates/scala/AGENTS.md +6 -0
  190. package/dist/templates/scala/README.md.tmpl +1 -1
  191. package/dist/templates/woocommerce/.nvmrc +1 -0
  192. package/dist/templates/woocommerce/AGENTS.md +49 -0
  193. package/dist/templates/woocommerce/README.md.tmpl +273 -0
  194. package/dist/templates/woocommerce/agents/order-reviewer/index.test.ts.tmpl +28 -0
  195. package/dist/templates/woocommerce/agents/order-reviewer/index.ts.tmpl +45 -0
  196. package/dist/templates/woocommerce/agents/store-agent/index.test.ts.tmpl +47 -0
  197. package/dist/templates/woocommerce/agents/store-agent/index.ts.tmpl +79 -0
  198. package/dist/templates/woocommerce/fixtures/order-created.json +67 -0
  199. package/dist/templates/woocommerce/flows/order-review/index.ts.tmpl +64 -0
  200. package/dist/templates/woocommerce/gitignore +8 -0
  201. package/dist/templates/woocommerce/guardrails/no-customer-contact-details/index.test.ts.tmpl +29 -0
  202. package/dist/templates/woocommerce/guardrails/no-customer-contact-details/index.ts.tmpl +74 -0
  203. package/dist/templates/woocommerce/kindgi.config.ts.tmpl +41 -0
  204. package/dist/templates/woocommerce/lib/fake-store.ts.tmpl +82 -0
  205. package/dist/templates/woocommerce/lib/woo.ts.tmpl +182 -0
  206. package/dist/templates/woocommerce/package.json.tmpl +30 -0
  207. package/dist/templates/woocommerce/pnpm-workspace.yaml +9 -0
  208. package/dist/templates/woocommerce/tools/check-order-event/index.test.ts.tmpl +76 -0
  209. package/dist/templates/woocommerce/tools/check-order-event/index.ts.tmpl +131 -0
  210. package/dist/templates/woocommerce/tools/find-orders/index.ts.tmpl +80 -0
  211. package/dist/templates/woocommerce/tools/publish-product/index.ts.tmpl +34 -0
  212. package/dist/templates/woocommerce/tools/refund/index.test.ts.tmpl +125 -0
  213. package/dist/templates/woocommerce/tools/refund/index.ts.tmpl +70 -0
  214. package/dist/templates/woocommerce/tools/refund-large/index.test.ts.tmpl +53 -0
  215. package/dist/templates/woocommerce/tools/refund-large/index.ts.tmpl +44 -0
  216. package/dist/templates/woocommerce/tools/set-price/index.ts.tmpl +36 -0
  217. package/dist/templates/woocommerce/tsconfig.json.tmpl +28 -0
  218. package/dist/templates/woocommerce/vitest.config.ts.tmpl +14 -0
  219. package/dist/test/defaults.d.ts +1 -1
  220. package/dist/test/defaults.d.ts.map +1 -1
  221. package/dist/test/defaults.js +2 -7
  222. package/dist/test/defaults.js.map +1 -1
  223. package/dist/test/runners.d.ts +6 -0
  224. package/dist/test/runners.d.ts.map +1 -1
  225. package/dist/test/runners.js +18 -1
  226. package/dist/test/runners.js.map +1 -1
  227. package/package.json +13 -13
@@ -0,0 +1,32 @@
1
+ export declare const LICENSE_KEY_PREFIX = "kgi_lk_";
2
+ /**
3
+ * The license signing keys a released runtime trusts, by `kid`: their
4
+ * Ed25519 public keys (base64). A new `kid` is added here, in a CLI
5
+ * release, before Kindgi signs with it: otherwise renewal refuses a
6
+ * correctly renewed key.
7
+ */
8
+ export declare const KINDGI_LICENSE_PUBLIC_KEYS: Readonly<Record<string, string>>;
9
+ export type LicenseUse = 'production' | 'non-production';
10
+ /** What a key says. */
11
+ export interface LicenseClaims {
12
+ readonly keyId: string;
13
+ readonly subject: string;
14
+ readonly name: string;
15
+ readonly use: LicenseUse;
16
+ readonly issuedAt: Date;
17
+ readonly expiresAt: Date;
18
+ }
19
+ export type LicenseKeyCheck = {
20
+ readonly kind: 'ok';
21
+ readonly claims: LicenseClaims;
22
+ } | {
23
+ readonly kind: 'err';
24
+ /** `malformed`: not a key; `unknown-key`: signed with a `kid` this CLI doesn't know; `bad-signature`. */
25
+ readonly reason: 'malformed' | 'unknown-key' | 'bad-signature';
26
+ };
27
+ /**
28
+ * Whether `key` is a license key Kindgi signed, and what it says. The
29
+ * dates aren't judged here: renewal compares them with the current key's.
30
+ */
31
+ export declare function checkLicenseKey(key: string, publicKeys?: Readonly<Record<string, string>>): LicenseKeyCheck;
32
+ //# sourceMappingURL=license-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-key.d.ts","sourceRoot":"","sources":["../../src/license/license-key.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEtE,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAEzD,uBAAuB;AACvB,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACvD;IACE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,yGAAyG;IACzG,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,GAAG,eAAe,CAAC;CAChE,CAAC;AAKN;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAA8B,GACxE,eAAe,CAyCjB"}
@@ -0,0 +1,91 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * A Kindgi license key, read and checked offline, as the runtime checks it
5
+ * at startup: `kgi_lk_<base64url payload>.<base64url signature>`, the
6
+ * payload JSON `{ v: 1, kid, sub, name, use, iat, exp }` (seconds), the
7
+ * signature Ed25519 over the ASCII bytes of `kgi_lk_<base64url payload>`
8
+ * by Kindgi's license signing key `kid`.
9
+ *
10
+ * `kindgi license renew` checks a renewed key with this before writing
11
+ * it, so a key the runtime would refuse is never written.
12
+ */
13
+ import { createPublicKey, verify } from 'node:crypto';
14
+ export const LICENSE_KEY_PREFIX = 'kgi_lk_';
15
+ /**
16
+ * The license signing keys a released runtime trusts, by `kid`: their
17
+ * Ed25519 public keys (base64). A new `kid` is added here, in a CLI
18
+ * release, before Kindgi signs with it: otherwise renewal refuses a
19
+ * correctly renewed key.
20
+ */
21
+ export const KINDGI_LICENSE_PUBLIC_KEYS = Object.freeze({
22
+ 'lk-2026-1': 'cIC6PF4tmqQzkH/MG1GVguOCHIEPBe8zLJWh64pGgp8=',
23
+ });
24
+ const BASE64URL = /^[A-Za-z0-9_-]+$/;
25
+ const USES = ['production', 'non-production'];
26
+ /**
27
+ * Whether `key` is a license key Kindgi signed, and what it says. The
28
+ * dates aren't judged here: renewal compares them with the current key's.
29
+ */
30
+ export function checkLicenseKey(key, publicKeys = KINDGI_LICENSE_PUBLIC_KEYS) {
31
+ const trimmed = key.trim();
32
+ const dot = trimmed.lastIndexOf('.');
33
+ if (!trimmed.startsWith(LICENSE_KEY_PREFIX) || dot <= LICENSE_KEY_PREFIX.length) {
34
+ return { kind: 'err', reason: 'malformed' };
35
+ }
36
+ const signed = trimmed.slice(0, dot);
37
+ const payloadPart = signed.slice(LICENSE_KEY_PREFIX.length);
38
+ const signaturePart = trimmed.slice(dot + 1);
39
+ if (!BASE64URL.test(payloadPart) || !BASE64URL.test(signaturePart)) {
40
+ return { kind: 'err', reason: 'malformed' };
41
+ }
42
+ const payload = parsePayload(payloadPart);
43
+ if (payload === undefined)
44
+ return { kind: 'err', reason: 'malformed' };
45
+ const publicKey = Object.hasOwn(publicKeys, payload.kid) ? publicKeys[payload.kid] : undefined;
46
+ const raw = publicKey === undefined ? undefined : Buffer.from(publicKey, 'base64');
47
+ if (raw === undefined || raw.length !== 32)
48
+ return { kind: 'err', reason: 'unknown-key' };
49
+ const signature = Buffer.from(signaturePart, 'base64url');
50
+ const ok = signature.length === 64 &&
51
+ verify(null, Buffer.from(signed, 'ascii'), createPublicKey({
52
+ key: { kty: 'OKP', crv: 'Ed25519', x: raw.toString('base64url') },
53
+ format: 'jwk',
54
+ }), signature);
55
+ if (!ok)
56
+ return { kind: 'err', reason: 'bad-signature' };
57
+ return {
58
+ kind: 'ok',
59
+ claims: {
60
+ keyId: payload.kid,
61
+ subject: payload.sub,
62
+ name: payload.name,
63
+ use: payload.use,
64
+ issuedAt: new Date(payload.iat * 1000),
65
+ expiresAt: new Date(payload.exp * 1000),
66
+ },
67
+ };
68
+ }
69
+ function parsePayload(part) {
70
+ let value;
71
+ try {
72
+ value = JSON.parse(Buffer.from(part, 'base64url').toString('utf8'));
73
+ }
74
+ catch {
75
+ return undefined;
76
+ }
77
+ if (typeof value !== 'object' || value === null)
78
+ return undefined;
79
+ const p = value;
80
+ const text = (v) => typeof v === 'string' && v.trim() !== '';
81
+ if (p.v !== 1 || !text(p.kid) || !text(p.sub) || !text(p.name))
82
+ return undefined;
83
+ if (!USES.includes(p.use))
84
+ return undefined;
85
+ if (!Number.isSafeInteger(p.iat) || !Number.isSafeInteger(p.exp))
86
+ return undefined;
87
+ if (p.exp <= p.iat)
88
+ return undefined;
89
+ return p;
90
+ }
91
+ //# sourceMappingURL=license-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-key.js","sourceRoot":"","sources":["../../src/license/license-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The renewal protocol, the deployment's side. A deployment renews its own
3
+ * license key with an Ed25519 key pair it made (`kindgi license enroll`):
4
+ * access.kindgi.com keeps only the public half, and each request is
5
+ * signed, so nothing replayable crosses the wire. The test vectors in
6
+ * `tests/license-protocol.test.ts` pin every byte.
7
+ *
8
+ * - **The renewer's private key**, as kept in the deployment's own secret
9
+ * store: `kgi_lrk_<the 32-byte seed, base64url>`. Never printed.
10
+ * - **The renewer id:** `lr_` and the first 22 characters of the base64url
11
+ * SHA-256 of the 32-byte public key.
12
+ * - **The enroll line** the person pastes on access.kindgi.com:
13
+ * `kgi_lrp_<public key>.<account>.<signature>`, each part base64url; the
14
+ * account is their GitHub login, lowercased; the signature covers
15
+ * `kindgi-license-enroll-v1\n<origin>\n<renewer id>\n<account>`.
16
+ * - **A renewal:** `POST <origin>/v1/renew`, the JSON body
17
+ * `{"renewerId","ts","nonce"}`, and the header
18
+ * `kindgi-renewer-signature`: Ed25519 over
19
+ * `kindgi-license-renew-v1\nPOST <origin>/v1/renew\n<base64url SHA-256 of
20
+ * the body>`.
21
+ */
22
+ import { type KeyObject } from 'node:crypto';
23
+ /** Where Kindgi's dev access lives: what enroll lines and renewals are signed for by default. */
24
+ export declare const KINDGI_ACCESS_ORIGIN = "https://access.kindgi.com";
25
+ export declare const RENEWER_PRIVATE_PREFIX = "kgi_lrk_";
26
+ export declare const RENEWER_PUBLIC_PREFIX = "kgi_lrp_";
27
+ export declare const RENEW_PATH = "/v1/renew";
28
+ export declare const RENEW_SIGNATURE_HEADER = "kindgi-renewer-signature";
29
+ /** A renewer's key pair, held in memory only. */
30
+ export interface RenewerKey {
31
+ readonly privateKey: KeyObject;
32
+ /** The 32-byte public key. */
33
+ readonly publicKey: Uint8Array;
34
+ readonly renewerId: string;
35
+ }
36
+ /** A new renewer key pair. */
37
+ export declare function generateRenewerKey(): RenewerKey;
38
+ /** The renewer id of a public key: `lr_` and 22 characters of its SHA-256. */
39
+ export declare function renewerIdOf(publicKey: Uint8Array): string;
40
+ /** The private key as the secret store keeps it: `kgi_lrk_<seed>`. */
41
+ export declare function encodeRenewerPrivateKey(key: RenewerKey): string;
42
+ /**
43
+ * The private key read back from the secret store; `undefined` when the
44
+ * value isn't one (an empty secret, another secret, a cut-off value).
45
+ */
46
+ export declare function decodeRenewerPrivateKey(value: string): RenewerKey | undefined;
47
+ /** What an enroll line's signature covers. */
48
+ export declare function enrollSigningInput(origin: string, renewerId: string, account: string): string;
49
+ /** The line to paste on access.kindgi.com: made for `account` (a GitHub login) there. */
50
+ export declare function enrollLine(key: RenewerKey, account: string, origin?: string): string;
51
+ /** What a renewal's signature covers: the service's origin and the body's digest. */
52
+ export declare function renewSigningInput(origin: string, body: Uint8Array): string;
53
+ /** A renewal request, signed: its body and the signature header's value. */
54
+ export declare function signRenewRequest(key: RenewerKey, options?: {
55
+ readonly origin?: string;
56
+ /** Seconds since the epoch. */
57
+ readonly now?: number;
58
+ readonly nonce?: string;
59
+ }): {
60
+ readonly body: string;
61
+ readonly signature: string;
62
+ };
63
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/license/protocol.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,KAAK,SAAS,EAOf,MAAM,aAAa,CAAC;AAErB,iGAAiG;AACjG,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAChE,eAAO,MAAM,sBAAsB,aAAa,CAAC;AACjD,eAAO,MAAM,qBAAqB,aAAa,CAAC;AAChD,eAAO,MAAM,UAAU,cAAc,CAAC;AACtC,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AAMjE,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,IAAI,UAAU,CAG/C;AAQD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAEzD;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAG/D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAa7E;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7F;AAED,yFAAyF;AACzF,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,EACf,MAAM,SAAuB,GAC5B,MAAM,CAWR;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAG1E;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,GAAE;IACP,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACpB,GACL;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAYvD"}
@@ -0,0 +1,102 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * The renewal protocol, the deployment's side. A deployment renews its own
5
+ * license key with an Ed25519 key pair it made (`kindgi license enroll`):
6
+ * access.kindgi.com keeps only the public half, and each request is
7
+ * signed, so nothing replayable crosses the wire. The test vectors in
8
+ * `tests/license-protocol.test.ts` pin every byte.
9
+ *
10
+ * - **The renewer's private key**, as kept in the deployment's own secret
11
+ * store: `kgi_lrk_<the 32-byte seed, base64url>`. Never printed.
12
+ * - **The renewer id:** `lr_` and the first 22 characters of the base64url
13
+ * SHA-256 of the 32-byte public key.
14
+ * - **The enroll line** the person pastes on access.kindgi.com:
15
+ * `kgi_lrp_<public key>.<account>.<signature>`, each part base64url; the
16
+ * account is their GitHub login, lowercased; the signature covers
17
+ * `kindgi-license-enroll-v1\n<origin>\n<renewer id>\n<account>`.
18
+ * - **A renewal:** `POST <origin>/v1/renew`, the JSON body
19
+ * `{"renewerId","ts","nonce"}`, and the header
20
+ * `kindgi-renewer-signature`: Ed25519 over
21
+ * `kindgi-license-renew-v1\nPOST <origin>/v1/renew\n<base64url SHA-256 of
22
+ * the body>`.
23
+ */
24
+ import { createHash, createPrivateKey, createPublicKey, generateKeyPairSync, randomBytes, sign, } from 'node:crypto';
25
+ /** Where Kindgi's dev access lives: what enroll lines and renewals are signed for by default. */
26
+ export const KINDGI_ACCESS_ORIGIN = 'https://access.kindgi.com';
27
+ export const RENEWER_PRIVATE_PREFIX = 'kgi_lrk_';
28
+ export const RENEWER_PUBLIC_PREFIX = 'kgi_lrp_';
29
+ export const RENEW_PATH = '/v1/renew';
30
+ export const RENEW_SIGNATURE_HEADER = 'kindgi-renewer-signature';
31
+ /** The PKCS#8 DER prefix of an Ed25519 private key, before its 32-byte seed. */
32
+ const ED25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
33
+ const BASE64URL = /^[A-Za-z0-9_-]+$/;
34
+ /** A new renewer key pair. */
35
+ export function generateRenewerKey() {
36
+ const { privateKey } = generateKeyPairSync('ed25519');
37
+ return renewerKeyFrom(privateKey);
38
+ }
39
+ function renewerKeyFrom(privateKey) {
40
+ const x = createPublicKey(privateKey).export({ format: 'jwk' }).x;
41
+ const publicKey = new Uint8Array(Buffer.from(x, 'base64url'));
42
+ return { privateKey, publicKey, renewerId: renewerIdOf(publicKey) };
43
+ }
44
+ /** The renewer id of a public key: `lr_` and 22 characters of its SHA-256. */
45
+ export function renewerIdOf(publicKey) {
46
+ return `lr_${createHash('sha256').update(publicKey).digest('base64url').slice(0, 22)}`;
47
+ }
48
+ /** The private key as the secret store keeps it: `kgi_lrk_<seed>`. */
49
+ export function encodeRenewerPrivateKey(key) {
50
+ const der = key.privateKey.export({ format: 'der', type: 'pkcs8' });
51
+ return `${RENEWER_PRIVATE_PREFIX}${Buffer.from(der.subarray(ED25519_PKCS8_PREFIX.length)).toString('base64url')}`;
52
+ }
53
+ /**
54
+ * The private key read back from the secret store; `undefined` when the
55
+ * value isn't one (an empty secret, another secret, a cut-off value).
56
+ */
57
+ export function decodeRenewerPrivateKey(value) {
58
+ const text = value.trim();
59
+ if (!text.startsWith(RENEWER_PRIVATE_PREFIX))
60
+ return undefined;
61
+ const encoded = text.slice(RENEWER_PRIVATE_PREFIX.length);
62
+ if (!BASE64URL.test(encoded))
63
+ return undefined;
64
+ const seed = Buffer.from(encoded, 'base64url');
65
+ if (seed.length !== 32)
66
+ return undefined;
67
+ const privateKey = createPrivateKey({
68
+ key: Buffer.concat([ED25519_PKCS8_PREFIX, seed]),
69
+ format: 'der',
70
+ type: 'pkcs8',
71
+ });
72
+ return renewerKeyFrom(privateKey);
73
+ }
74
+ /** What an enroll line's signature covers. */
75
+ export function enrollSigningInput(origin, renewerId, account) {
76
+ return `kindgi-license-enroll-v1\n${origin}\n${renewerId}\n${account.toLowerCase()}`;
77
+ }
78
+ /** The line to paste on access.kindgi.com: made for `account` (a GitHub login) there. */
79
+ export function enrollLine(key, account, origin = KINDGI_ACCESS_ORIGIN) {
80
+ const signature = sign(null, Buffer.from(enrollSigningInput(origin, key.renewerId, account), 'utf8'), key.privateKey);
81
+ return [
82
+ `${RENEWER_PUBLIC_PREFIX}${Buffer.from(key.publicKey).toString('base64url')}`,
83
+ Buffer.from(account.toLowerCase(), 'utf8').toString('base64url'),
84
+ signature.toString('base64url'),
85
+ ].join('.');
86
+ }
87
+ /** What a renewal's signature covers: the service's origin and the body's digest. */
88
+ export function renewSigningInput(origin, body) {
89
+ const digest = createHash('sha256').update(body).digest('base64url');
90
+ return `kindgi-license-renew-v1\nPOST ${origin}${RENEW_PATH}\n${digest}`;
91
+ }
92
+ /** A renewal request, signed: its body and the signature header's value. */
93
+ export function signRenewRequest(key, options = {}) {
94
+ const body = JSON.stringify({
95
+ renewerId: key.renewerId,
96
+ ts: options.now ?? Math.floor(Date.now() / 1000),
97
+ nonce: options.nonce ?? randomBytes(16).toString('base64url'),
98
+ });
99
+ const signature = sign(null, Buffer.from(renewSigningInput(options.origin ?? KINDGI_ACCESS_ORIGIN, Buffer.from(body))), key.privateKey).toString('base64url');
100
+ return { body, signature };
101
+ }
102
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/license/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * One renewal, the deployment's side: read the current license key and the
3
+ * renewer's private key from where the deployment keeps them, ask
4
+ * access.kindgi.com (a signed `POST /v1/renew`), check the answer offline,
5
+ * and write it only when it's a new key the runtime will accept.
6
+ *
7
+ * The answer is checked before anything is written: signed by a key a
8
+ * released runtime trusts, for the same licensee and use as the current
9
+ * key, and expiring no earlier. A wrong, rolled-back or someone else's key
10
+ * is never written. Most days the key is unchanged and nothing is written.
11
+ */
12
+ import { type LicenseClaims } from './license-key.js';
13
+ import type { SecretStore } from './stores.js';
14
+ export interface RenewDeps {
15
+ readonly fetch?: typeof fetch;
16
+ /** Milliseconds since the epoch. */
17
+ readonly now?: () => number;
18
+ readonly publicKeys?: Readonly<Record<string, string>>;
19
+ readonly timeoutMs?: number;
20
+ }
21
+ /** What `kindgi license renew` runs with: tests hand in their own clock and fetch. */
22
+ export interface LicenseCommandDeps {
23
+ readonly renew?: RenewDeps;
24
+ }
25
+ export interface RenewInput {
26
+ /** Where the license key is kept; the new one is written there. */
27
+ readonly key: SecretStore;
28
+ /** Where the renewer's private key is kept (`kindgi license enroll` wrote it). */
29
+ readonly renewer: SecretStore;
30
+ /** access.kindgi.com, or another instance's origin. */
31
+ readonly origin?: string;
32
+ }
33
+ export type RenewOutcome = {
34
+ readonly kind: 'renewed' | 'unchanged';
35
+ readonly claims: LicenseClaims;
36
+ readonly renewerId: string;
37
+ }
38
+ /** The service said no: its code and message (`renewer-stopped`, `key-revoked`, …). */
39
+ | {
40
+ readonly kind: 'refused';
41
+ readonly status: number;
42
+ readonly error: string;
43
+ readonly message: string;
44
+ readonly renewerId?: string;
45
+ }
46
+ /** Nothing to renew with, nothing usable came back, or the service couldn't be reached. */
47
+ | {
48
+ readonly kind: 'failed';
49
+ readonly message: string;
50
+ readonly renewerId?: string;
51
+ };
52
+ export declare function renewLicense(input: RenewInput, deps?: RenewDeps): Promise<RenewOutcome>;
53
+ /**
54
+ * What stopped a request, as exactly as the error says it. fetch's own
55
+ * `fetch failed` says nothing; its cause does (`connect ECONNREFUSED …`,
56
+ * `getaddrinfo ENOTFOUND …`, a certificate's), or just its code.
57
+ */
58
+ export declare function networkReason(err: unknown): string;
59
+ //# sourceMappingURL=renew.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renew.d.ts","sourceRoot":"","sources":["../../src/license/renew.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,EAEL,KAAK,aAAa,EAGnB,MAAM,kBAAkB,CAAC;AAS1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAC9B,oCAAoC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,sFAAsF;AACtF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,YAAY,GACpB;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACH,uFAAuF;GACrF;IACE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AACH,2FAA2F;GACzF;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,wBAAsB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,SAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAqDjG;AA+DD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAWlD"}
@@ -0,0 +1,153 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * One renewal, the deployment's side: read the current license key and the
5
+ * renewer's private key from where the deployment keeps them, ask
6
+ * access.kindgi.com (a signed `POST /v1/renew`), check the answer offline,
7
+ * and write it only when it's a new key the runtime will accept.
8
+ *
9
+ * The answer is checked before anything is written: signed by a key a
10
+ * released runtime trusts, for the same licensee and use as the current
11
+ * key, and expiring no earlier. A wrong, rolled-back or someone else's key
12
+ * is never written. Most days the key is unchanged and nothing is written.
13
+ */
14
+ import { KINDGI_LICENSE_PUBLIC_KEYS, checkLicenseKey, } from './license-key.js';
15
+ import { KINDGI_ACCESS_ORIGIN, RENEW_PATH, RENEW_SIGNATURE_HEADER, decodeRenewerPrivateKey, signRenewRequest, } from './protocol.js';
16
+ export async function renewLicense(input, deps = {}) {
17
+ const origin = (input.origin ?? KINDGI_ACCESS_ORIGIN).replace(/\/+$/, '');
18
+ const publicKeys = deps.publicKeys ?? KINDGI_LICENSE_PUBLIC_KEYS;
19
+ const held = await whatIsHeld(input, publicKeys);
20
+ if (held.kind === 'failed')
21
+ return held;
22
+ const { renewerId } = held.renewer;
23
+ const request = signRenewRequest(held.renewer, {
24
+ origin,
25
+ now: Math.floor((deps.now ?? Date.now)() / 1000),
26
+ });
27
+ const asked = await ask(origin, request, deps);
28
+ if (asked.kind === 'unreachable') {
29
+ return {
30
+ kind: 'failed',
31
+ renewerId,
32
+ message: `${origin} couldn't be reached (${asked.reason}). The key in ${input.key.describe} is unchanged; try again later.`,
33
+ };
34
+ }
35
+ const { res, body } = asked;
36
+ if (!res.ok) {
37
+ // The service's own refusals name their code; any other error answer
38
+ // (a 5xx, a proxy's page) refuses nothing: the next run may succeed.
39
+ if (typeof body.error !== 'string') {
40
+ return {
41
+ kind: 'failed',
42
+ renewerId,
43
+ message: `${origin} answered ${res.status}. The key in ${input.key.describe} is unchanged; try again later.`,
44
+ };
45
+ }
46
+ return {
47
+ kind: 'refused',
48
+ status: res.status,
49
+ error: body.error,
50
+ message: typeof body.message === 'string' ? body.message : `${origin} answered ${res.status}.`,
51
+ renewerId,
52
+ };
53
+ }
54
+ const answer = typeof body.licenseKey === 'string' ? body.licenseKey.trim() : '';
55
+ const renewed = checkLicenseKey(answer, publicKeys);
56
+ const problem = whyNotWritten(renewed, held.current);
57
+ if (renewed.kind === 'err' || problem !== undefined) {
58
+ return {
59
+ kind: 'failed',
60
+ renewerId,
61
+ message: `The key ${origin} sent wasn't written: ${problem}. The key in ${input.key.describe} is unchanged.`,
62
+ };
63
+ }
64
+ if (answer === held.currentKey)
65
+ return { kind: 'unchanged', claims: renewed.claims, renewerId };
66
+ await input.key.write(answer);
67
+ return { kind: 'renewed', claims: renewed.claims, renewerId };
68
+ }
69
+ /** The current key (checked) and the renewer's key, or what's missing. */
70
+ async function whatIsHeld(input, publicKeys) {
71
+ const currentKey = await input.key.read();
72
+ if (currentKey === undefined) {
73
+ return {
74
+ kind: 'failed',
75
+ message: `There's no license key in ${input.key.describe} to renew. The first one comes from signing in at access.kindgi.com; put it there.`,
76
+ };
77
+ }
78
+ const current = checkLicenseKey(currentKey, publicKeys);
79
+ if (current.kind === 'err') {
80
+ return {
81
+ kind: 'failed',
82
+ message: `The value in ${input.key.describe} isn't a license key this CLI can check (${current.reason}).`,
83
+ };
84
+ }
85
+ const renewerValue = await input.renewer.read();
86
+ const renewer = renewerValue === undefined ? undefined : decodeRenewerPrivateKey(renewerValue);
87
+ if (renewer === undefined) {
88
+ return {
89
+ kind: 'failed',
90
+ message: `There's no renewer key in ${input.renewer.describe}. Enroll this deployment first: kindgi license enroll --for <your GitHub login> --renewer <where to keep its key>.`,
91
+ };
92
+ }
93
+ return { kind: 'held', currentKey, current: current.claims, renewer };
94
+ }
95
+ /** One signed request; a network failure is said, never thrown. */
96
+ async function ask(origin, request, deps) {
97
+ try {
98
+ const res = await (deps.fetch ?? fetch)(`${origin}${RENEW_PATH}`, {
99
+ method: 'POST',
100
+ headers: { 'content-type': 'application/json', [RENEW_SIGNATURE_HEADER]: request.signature },
101
+ body: request.body,
102
+ signal: AbortSignal.timeout(deps.timeoutMs ?? 30_000),
103
+ });
104
+ const body = (await res.json().catch(() => ({})));
105
+ return { kind: 'answered', res, body };
106
+ }
107
+ catch (cause) {
108
+ return { kind: 'unreachable', reason: networkReason(cause) };
109
+ }
110
+ }
111
+ /**
112
+ * What stopped a request, as exactly as the error says it. fetch's own
113
+ * `fetch failed` says nothing; its cause does (`connect ECONNREFUSED …`,
114
+ * `getaddrinfo ENOTFOUND …`, a certificate's), or just its code.
115
+ */
116
+ export function networkReason(err) {
117
+ const said = [];
118
+ let at = err;
119
+ for (let depth = 0; at instanceof Error && depth < 4; depth++) {
120
+ if (at.name === 'TimeoutError')
121
+ return 'no answer in time';
122
+ const code = at.code;
123
+ const text = at.message !== '' ? at.message : typeof code === 'string' ? code : '';
124
+ if (text !== '' && text !== 'fetch failed')
125
+ said.push(text);
126
+ at = at.cause;
127
+ }
128
+ return said.at(-1) ?? (err instanceof Error && err.message !== '' ? err.message : String(err));
129
+ }
130
+ /**
131
+ * Why an answer mustn't be written, or `undefined`: a key a released
132
+ * runtime accepts, for the same licensee and use, expiring no earlier.
133
+ */
134
+ function whyNotWritten(renewed, current) {
135
+ if (renewed.kind === 'err') {
136
+ if (renewed.reason === 'unknown-key') {
137
+ return "it's signed with a key this CLI doesn't know yet (unknown-key): update the CLI, then try again";
138
+ }
139
+ if (renewed.reason === 'malformed') {
140
+ return 'the answer held no license key (malformed): a page from a proxy or another server, perhaps';
141
+ }
142
+ return `it isn't a key a released runtime accepts (${renewed.reason})`;
143
+ }
144
+ const next = renewed.claims;
145
+ if (next.subject !== current.subject)
146
+ return `it's for ${next.name}, not ${current.name}`;
147
+ if (next.use !== current.use)
148
+ return `it's a ${next.use} key, not a ${current.use} one`;
149
+ if (next.expiresAt < current.expiresAt)
150
+ return 'it expires before the current one';
151
+ return undefined;
152
+ }
153
+ //# sourceMappingURL=renew.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renew.js","sourceRoot":"","sources":["../../src/license/renew.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type CloudDeps } from './cloud.js';
2
+ export interface SecretStore {
3
+ /** The value, trimmed; `undefined` when there's none yet (no file, no line, empty). */
4
+ read(): Promise<string | undefined>;
5
+ /** Keep `value` as the new value. */
6
+ write(value: string): Promise<void>;
7
+ /** Where, for messages: never the value. */
8
+ readonly describe: string;
9
+ }
10
+ export declare class SecretRefError extends Error {
11
+ }
12
+ /** Runs a cloud's CLI (`gcloud`, `az`, `aws`) for a token: its stdout. */
13
+ export declare const runCloudCli: CloudDeps['run'];
14
+ /** The store a reference names. Throws `SecretRefError`, saying what a reference looks like. */
15
+ export declare function secretStoreFor(ref: string, options?: {
16
+ readonly cwd?: string;
17
+ readonly cloud?: CloudDeps;
18
+ }): SecretStore;
19
+ //# sourceMappingURL=stores.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../src/license/stores.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,KAAK,SAAS,EAAoC,MAAM,YAAY,CAAC;AAE9E,MAAM,WAAW,WAAW;IAC1B,uFAAuF;IACvF,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACpC,qCAAqC;IACrC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAI5C,0EAA0E;AAC1E,eAAO,MAAM,WAAW,EAAE,SAAS,CAAC,KAAK,CAKrC,CAAC;AA0BL,gGAAgG;AAChG,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAO,GAClE,WAAW,CAWb"}