@homeflare/alchemy 0.23.0 → 0.25.0

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 (177) hide show
  1. package/README.md +25 -1
  2. package/dist/litellm/client.d.ts +76 -0
  3. package/dist/litellm/client.d.ts.map +1 -0
  4. package/dist/litellm/credentials.d.ts +48 -0
  5. package/dist/litellm/credentials.d.ts.map +1 -0
  6. package/dist/litellm/fake-litellm.d.ts +36 -0
  7. package/dist/litellm/fake-litellm.d.ts.map +1 -0
  8. package/dist/litellm/fake-stack.d.ts +30 -0
  9. package/dist/litellm/fake-stack.d.ts.map +1 -0
  10. package/dist/litellm/generated/pass-through.d.ts +71 -0
  11. package/dist/litellm/generated/pass-through.d.ts.map +1 -0
  12. package/dist/litellm/index.d.ts +13 -0
  13. package/dist/litellm/index.d.ts.map +1 -0
  14. package/dist/litellm/index.js +270 -0
  15. package/dist/litellm/index.js.map +14 -0
  16. package/dist/litellm/pass-through-endpoint.d.ts +94 -0
  17. package/dist/litellm/pass-through-endpoint.d.ts.map +1 -0
  18. package/dist/litellm/pass-through-form.d.ts +40 -0
  19. package/dist/litellm/pass-through-form.d.ts.map +1 -0
  20. package/dist/litellm/providers.d.ts +16 -0
  21. package/dist/litellm/providers.d.ts.map +1 -0
  22. package/dist/paperless/client.d.ts +37 -0
  23. package/dist/paperless/client.d.ts.map +1 -0
  24. package/dist/paperless/constraint-guard.d.ts +19 -0
  25. package/dist/paperless/constraint-guard.d.ts.map +1 -0
  26. package/dist/paperless/constraints.d.ts +50 -0
  27. package/dist/paperless/constraints.d.ts.map +1 -0
  28. package/dist/paperless/credentials.d.ts +40 -0
  29. package/dist/paperless/credentials.d.ts.map +1 -0
  30. package/dist/paperless/custom-field.d.ts +75 -0
  31. package/dist/paperless/custom-field.d.ts.map +1 -0
  32. package/dist/paperless/document-type.d.ts +30 -0
  33. package/dist/paperless/document-type.d.ts.map +1 -0
  34. package/dist/paperless/errors.d.ts +49 -0
  35. package/dist/paperless/errors.d.ts.map +1 -0
  36. package/dist/paperless/fake-paperless.d.ts +39 -0
  37. package/dist/paperless/fake-paperless.d.ts.map +1 -0
  38. package/dist/paperless/generated/constraints/index.d.ts +13 -0
  39. package/dist/paperless/generated/constraints/index.d.ts.map +1 -0
  40. package/dist/paperless/generated/constraints/paperless-custom_fields.d.ts +21 -0
  41. package/dist/paperless/generated/constraints/paperless-custom_fields.d.ts.map +1 -0
  42. package/dist/paperless/generated/constraints/paperless-document_types.d.ts +21 -0
  43. package/dist/paperless/generated/constraints/paperless-document_types.d.ts.map +1 -0
  44. package/dist/paperless/generated/constraints/paperless-storage_paths.d.ts +21 -0
  45. package/dist/paperless/generated/constraints/paperless-storage_paths.d.ts.map +1 -0
  46. package/dist/paperless/generated/constraints/paperless-tags.d.ts +21 -0
  47. package/dist/paperless/generated/constraints/paperless-tags.d.ts.map +1 -0
  48. package/dist/paperless/generated/types/custom-fields.d.ts +23 -0
  49. package/dist/paperless/generated/types/custom-fields.d.ts.map +1 -0
  50. package/dist/paperless/generated/types/document-types.d.ts +39 -0
  51. package/dist/paperless/generated/types/document-types.d.ts.map +1 -0
  52. package/dist/paperless/generated/types/index.d.ts +10 -0
  53. package/dist/paperless/generated/types/index.d.ts.map +1 -0
  54. package/dist/paperless/generated/types/storage-paths.d.ts +31 -0
  55. package/dist/paperless/generated/types/storage-paths.d.ts.map +1 -0
  56. package/dist/paperless/generated/types/tags.d.ts +37 -0
  57. package/dist/paperless/generated/types/tags.d.ts.map +1 -0
  58. package/dist/paperless/index.d.ts +19 -0
  59. package/dist/paperless/index.d.ts.map +1 -0
  60. package/dist/paperless/index.js +524 -0
  61. package/dist/paperless/index.js.map +26 -0
  62. package/dist/paperless/matching-locate.d.ts +33 -0
  63. package/dist/paperless/matching-locate.d.ts.map +1 -0
  64. package/dist/paperless/matching-types.d.ts +60 -0
  65. package/dist/paperless/matching-types.d.ts.map +1 -0
  66. package/dist/paperless/matching.d.ts +61 -0
  67. package/dist/paperless/matching.d.ts.map +1 -0
  68. package/dist/paperless/providers.d.ts +15 -0
  69. package/dist/paperless/providers.d.ts.map +1 -0
  70. package/dist/paperless/storage-path.d.ts +32 -0
  71. package/dist/paperless/storage-path.d.ts.map +1 -0
  72. package/dist/paperless/tag.d.ts +47 -0
  73. package/dist/paperless/tag.d.ts.map +1 -0
  74. package/dist/postgres/connection.d.ts +50 -0
  75. package/dist/postgres/connection.d.ts.map +1 -0
  76. package/dist/postgres/database-attrs.d.ts +79 -0
  77. package/dist/postgres/database-attrs.d.ts.map +1 -0
  78. package/dist/postgres/database-sql.d.ts +73 -0
  79. package/dist/postgres/database-sql.d.ts.map +1 -0
  80. package/dist/postgres/database.d.ts +63 -0
  81. package/dist/postgres/database.d.ts.map +1 -0
  82. package/dist/postgres/errors.d.ts +86 -0
  83. package/dist/postgres/errors.d.ts.map +1 -0
  84. package/dist/postgres/fake-sql.d.ts +22 -0
  85. package/dist/postgres/fake-sql.d.ts.map +1 -0
  86. package/dist/postgres/index.d.ts +16 -0
  87. package/dist/postgres/index.d.ts.map +1 -0
  88. package/dist/postgres/index.js +238 -0
  89. package/dist/postgres/index.js.map +15 -0
  90. package/dist/postgres/providers.d.ts +14 -0
  91. package/dist/postgres/providers.d.ts.map +1 -0
  92. package/dist/proxmox/index.js.map +2 -2
  93. package/dist/proxmox/zfs-pool.d.ts +10 -2
  94. package/dist/proxmox/zfs-pool.d.ts.map +1 -1
  95. package/dist/release/archive.d.ts +6 -2
  96. package/dist/release/archive.d.ts.map +1 -1
  97. package/dist/release/binary-form.d.ts +14 -9
  98. package/dist/release/binary-form.d.ts.map +1 -1
  99. package/dist/release/binary-pins.d.ts +17 -0
  100. package/dist/release/binary-pins.d.ts.map +1 -0
  101. package/dist/release/catalog.d.ts.map +1 -1
  102. package/dist/release/index.js +90 -40
  103. package/dist/release/index.js.map +8 -7
  104. package/dist/release/tar.d.ts +9 -2
  105. package/dist/release/tar.d.ts.map +1 -1
  106. package/docs/litellm.md +110 -0
  107. package/docs/paperless.md +115 -0
  108. package/docs/peers.md +8 -1
  109. package/docs/postgres.md +125 -0
  110. package/docs/release-binary-catalogs.md +40 -4
  111. package/docs/release-binary-refusals.md +22 -8
  112. package/docs/release-binary-upstream.md +33 -15
  113. package/package.json +14 -1
  114. package/src/litellm/client.ts +195 -0
  115. package/src/litellm/credentials.ts +73 -0
  116. package/src/litellm/fake-litellm.ts +114 -0
  117. package/src/litellm/fake-stack.ts +100 -0
  118. package/src/litellm/generated/pass-through.ts +73 -0
  119. package/src/litellm/index.ts +42 -0
  120. package/src/litellm/pass-through-endpoint-delete-swallow.test.ts +66 -0
  121. package/src/litellm/pass-through-endpoint-replace.test.ts +84 -0
  122. package/src/litellm/pass-through-endpoint.test.ts +208 -0
  123. package/src/litellm/pass-through-endpoint.ts +258 -0
  124. package/src/litellm/pass-through-form.test.ts +128 -0
  125. package/src/litellm/pass-through-form.ts +136 -0
  126. package/src/litellm/providers.ts +19 -0
  127. package/src/paperless/client.ts +88 -0
  128. package/src/paperless/constraint-guard.ts +50 -0
  129. package/src/paperless/constraints.test.ts +74 -0
  130. package/src/paperless/constraints.ts +111 -0
  131. package/src/paperless/credentials.ts +69 -0
  132. package/src/paperless/custom-field.test.ts +74 -0
  133. package/src/paperless/custom-field.ts +95 -0
  134. package/src/paperless/document-type.ts +74 -0
  135. package/src/paperless/errors.ts +62 -0
  136. package/src/paperless/fake-paperless.ts +156 -0
  137. package/src/paperless/generated/constraints/index.ts +23 -0
  138. package/src/paperless/generated/constraints/paperless-custom_fields.ts +29 -0
  139. package/src/paperless/generated/constraints/paperless-document_types.ts +32 -0
  140. package/src/paperless/generated/constraints/paperless-storage_paths.ts +34 -0
  141. package/src/paperless/generated/constraints/paperless-tags.ts +34 -0
  142. package/src/paperless/generated/types/custom-fields.ts +23 -0
  143. package/src/paperless/generated/types/document-types.ts +30 -0
  144. package/src/paperless/generated/types/index.ts +9 -0
  145. package/src/paperless/generated/types/storage-paths.ts +31 -0
  146. package/src/paperless/generated/types/tags.ts +37 -0
  147. package/src/paperless/index.ts +56 -0
  148. package/src/paperless/matching-identity.test.ts +194 -0
  149. package/src/paperless/matching-locate.ts +104 -0
  150. package/src/paperless/matching-types.ts +61 -0
  151. package/src/paperless/matching.test.ts +128 -0
  152. package/src/paperless/matching.ts +239 -0
  153. package/src/paperless/providers.ts +27 -0
  154. package/src/paperless/storage-path.ts +78 -0
  155. package/src/paperless/tag.ts +91 -0
  156. package/src/postgres/connection.ts +62 -0
  157. package/src/postgres/database-attrs.ts +87 -0
  158. package/src/postgres/database-bigint-serialization.test.ts +140 -0
  159. package/src/postgres/database-lifecycle.test.ts +113 -0
  160. package/src/postgres/database-provenance.test.ts +118 -0
  161. package/src/postgres/database-refusals.test.ts +135 -0
  162. package/src/postgres/database-sql.ts +174 -0
  163. package/src/postgres/database.ts +193 -0
  164. package/src/postgres/errors.ts +131 -0
  165. package/src/postgres/fake-sql.ts +123 -0
  166. package/src/postgres/fixtures/pg-REL_18_6-create-database-synopsis.txt +26 -0
  167. package/src/postgres/fixtures/pg-REL_18_6-pg_database.h.txt +67 -0
  168. package/src/postgres/index.ts +30 -0
  169. package/src/postgres/providers.ts +16 -0
  170. package/src/proxmox/zfs-pool.ts +10 -2
  171. package/src/release/archive.ts +10 -4
  172. package/src/release/binary-form.ts +24 -76
  173. package/src/release/binary-pins.ts +95 -0
  174. package/src/release/binary-root.test.ts +122 -0
  175. package/src/release/catalog.ts +10 -2
  176. package/src/release/tar-root.test.ts +114 -0
  177. package/src/release/tar.ts +78 -12
@@ -15,10 +15,25 @@
15
15
  * non-zero bytes after the end marker; an archive that stops before it.
16
16
  * ★ GNU LONG NAMES ('L', 'K') AND PAX HEADERS ('x', 'g') ARE REFUSED, NOT INTERPRETED. Each renames
17
17
  * the entry after it: a reader that honours them must get them exactly right to match exactly,
18
- * and one that skips them matches under the wrong name. The four pinned archives use neither
19
- * (measured 2026-09-22 with `tar -tvzf` on each: every entry a root-level regular file with a
20
- * short name), so refusing costs nothing today, and a vendor format change becomes a refusal that
21
- * says what changed instead of a silent mis-read.
18
+ * and one that skips them matches under the wrong name. Refusing costs nothing for an archive
19
+ * that carries neither, and a vendor format change becomes a refusal that says what changed
20
+ * instead of a silent mis-read.
21
+ * ★ AN OPTIONAL `root`: ONE DECLARED LEADING DIRECTORY, STRIPPED, NEVER GUESSED. Measured
22
+ * 2026-09-23: `gh api repos/<o>/<r>/releases/tags/<tag>` for each asset URL and digest, the
23
+ * archive downloaded into a scratch directory (never executed), re-hashed against GitHub's
24
+ * `digest`, then read by THIS reader (a driver script importing `tarReader`) both before and
25
+ * after this change — refused whole either way without `root`, and, with it, parsed to
26
+ * completion: `alertmanager-0.33.1.darwin-arm64.tar.gz` (37,247,168 B),
27
+ * `blackbox_exporter-0.28.0.darwin-arm64.tar.gz` (15,705,022 B),
28
+ * `node_exporter-1.12.1.darwin-arm64.tar.gz` (5,368,643 B) and
29
+ * `postgres_exporter-0.20.1.darwin-arm64.tar.gz` (10,072,235 B) each recompute to GitHub's own
30
+ * `digest`, and each wraps every entry in exactly one directory (typeflag '5', size 0, first)
31
+ * named `<binary>-<version>.darwin-arm64/`, holding only root-level regular files (the binary,
32
+ * `LICENSE`, `NOTICE`, and for alertmanager also `amtool` and `alertmanager.yml`) — no PAX or
33
+ * GNU long-name entries, so this reader's refusal of both stays exactly as costly as before.
34
+ * Without `root`, EVERY refusal above still holds byte-for-byte: a directory entry — the wrapper
35
+ * included — is refused the same way it always was (docs/release-binary-catalogs.md,
36
+ * docs/release-binary-upstream.md gap 11).
22
37
  */
23
38
  import { ArchiveRefused } from './refused.ts';
24
39
 
@@ -101,8 +116,15 @@ export type TarContents = {
101
116
  readonly names: readonly string[];
102
117
  };
103
118
 
104
- /** A push parser: `push` each chunk of the unzipped stream, then `finish`. Either may throw. */
105
- export const tarReader = (wanted: ReadonlySet<string>) => {
119
+ /**
120
+ * A push parser: `push` each chunk of the unzipped stream, then `finish`. Either may throw.
121
+ *
122
+ * @param root When given, exactly one typeflag-'5' entry named `<root>/`, size 0, is accepted and
123
+ * dropped rather than refused as a directory; every OTHER entry name must begin with the SEGMENT
124
+ * `<root>/` (a `<root>-evil/x` sibling does not) and is reported, matched and kept under that
125
+ * prefix stripped off. Omitted, behaviour is byte-identical to a reader with no root at all.
126
+ */
127
+ export const tarReader = (wanted: ReadonlySet<string>, root?: string) => {
106
128
  const header = new Uint8Array(BLOCK);
107
129
  const members = new Map<string, Uint8Array>();
108
130
  const names: string[] = [];
@@ -114,6 +136,8 @@ export const tarReader = (wanted: ReadonlySet<string>) => {
114
136
  let zeros = 0;
115
137
  let name = '';
116
138
  let parts: Uint8Array[] | undefined;
139
+ let rootSeen = false;
140
+ const rootPrefix = root === undefined ? undefined : `${root}/`;
117
141
 
118
142
  const endEntry = () => {
119
143
  if (parts !== undefined) members.set(name, concatBytes(parts));
@@ -134,18 +158,57 @@ export const tarReader = (wanted: ReadonlySet<string>) => {
134
158
  if (!posix && magic !== 'ustar \u0000')
135
159
  throw refuse('an entry header is neither ustar nor GNU');
136
160
  const prefix = posix ? text(header, 345, 155) : '';
137
- name = prefix === '' ? text(header, 0, 100) : `${prefix}/${text(header, 0, 100)}`;
138
- const problem = nameProblem(name);
139
- if (problem !== undefined) throw refuse(`entry ${JSON.stringify(name)} ${problem}`);
161
+ const rawName = prefix === '' ? text(header, 0, 100) : `${prefix}/${text(header, 0, 100)}`;
162
+ const problem = nameProblem(rawName);
163
+ if (problem !== undefined) throw refuse(`entry ${JSON.stringify(rawName)} ${problem}`);
164
+ // ★ THE DECLARED ROOT IS RECOGNISED BEFORE THE GENERAL TYPE CHECK, and only by exact name: a
165
+ // directory entry under any other name — nested, or a second copy of the root itself — still
166
+ // falls through to that check below and is refused as a directory, same as with no root.
167
+ if (rootPrefix !== undefined && rawName === rootPrefix) {
168
+ if (rootSeen) {
169
+ // ⚠️ Whatever type THIS entry is, its name is already taken: refused for reusing the
170
+ // root's name, not necessarily for being a second directory (it need not be one).
171
+ throw refuse(`entry "${rawName}" reuses the declared root's own name, appearing twice`);
172
+ }
173
+ const type = String.fromCharCode(header[156] ?? 0);
174
+ const size = octal(header, 124, 12, `entry "${rawName}"'s size`);
175
+ if (type !== '5' || size !== 0) {
176
+ throw refuse(`entry "${rawName}" is the declared root but is not an empty directory`);
177
+ }
178
+ rootSeen = true;
179
+ phase = 'header';
180
+ return;
181
+ }
182
+ let stripped = rawName;
183
+ if (rootPrefix !== undefined) {
184
+ if (!rawName.startsWith(rootPrefix)) {
185
+ throw refuse(`entry "${rawName}" is outside the declared root "${rootPrefix}"`);
186
+ }
187
+ // ⛔ THE STRIPPED NAME GETS THE SAME SAFETY CHECK AS A RAW ONE. `rawName` already passed
188
+ // `nameProblem` above, but stripping a prefix can UNCOVER a `/` or `..` that was hiding
189
+ // past it: `<root>//x` is not absolute as a whole name, but strips to `/x`, which is —
190
+ // the exact thing this reader refuses a plain (rootless) archive for. MEASURED: without
191
+ // this check, `<root>//x` beside `<root>/x` parsed to completion as two distinct entries,
192
+ // `x` and `/x`, neither refused. `stripped` can never be empty here: the one raw name that
193
+ // strips to '' is `rootPrefix` itself, handled above.
194
+ stripped = rawName.slice(rootPrefix.length);
195
+ const strippedProblem = nameProblem(stripped);
196
+ if (strippedProblem !== undefined) {
197
+ throw refuse(
198
+ `entry "${rawName}" strips to ${JSON.stringify(stripped)}, which ${strippedProblem}`,
199
+ );
200
+ }
201
+ }
202
+ name = stripped;
140
203
  const type = String.fromCharCode(header[156] ?? 0);
141
204
  if (type !== '0' && type !== '\0') {
142
205
  const kind = KINDS[type] ?? `of unknown type ${JSON.stringify(type)}`;
143
- throw refuse(`entry "${name}" is ${kind}; only regular files are accepted`);
206
+ throw refuse(`entry "${rawName}" is ${kind}; only regular files are accepted`);
144
207
  }
145
- if (seen.has(name)) throw refuse(`entry "${name}" appears twice`);
208
+ if (seen.has(name)) throw refuse(`entry "${rawName}" appears twice`);
146
209
  seen.add(name);
147
210
  names.push(name);
148
- remaining = octal(header, 124, 12, `entry "${name}"'s size`);
211
+ remaining = octal(header, 124, 12, `entry "${rawName}"'s size`);
149
212
  padding = (BLOCK - (remaining % BLOCK)) % BLOCK;
150
213
  parts = wanted.has(name) ? [] : undefined;
151
214
  phase = 'data';
@@ -188,6 +251,9 @@ export const tarReader = (wanted: ReadonlySet<string>) => {
188
251
 
189
252
  const finish = (): TarContents => {
190
253
  if (phase !== 'end') throw refuse('the archive stops before its end-of-archive marker');
254
+ if (rootPrefix !== undefined && !rootSeen) {
255
+ throw refuse(`the declared root "${rootPrefix}" never appears in the archive`);
256
+ }
191
257
  return { members, names };
192
258
  };
193
259