@hasna/hooks 0.9.5 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ export type NativeSafetyName = "trash-guard" | "workspace-repos-guard";
2
+ export interface NativeSafetyBinding {
3
+ name: NativeSafetyName;
4
+ runtime: string;
5
+ runtimeSHA256: string;
6
+ worker: string;
7
+ workerSHA256: string;
8
+ home: string;
9
+ path: string;
10
+ }
11
+ export declare function isNativeSafetyName(name: string): name is NativeSafetyName;
12
+ export declare function buildNativeSafetyCommand(binding: NativeSafetyBinding): string;
13
+ export declare function nativeSafetyRegistration(command: string): NativeSafetyName | undefined;
14
+ /** Built-in capability only: no registry, custom source, profile or app store. */
15
+ export declare function installedNativeSafetyCommand(name: NativeSafetyName): string;
package/dist/openapi.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export declare const openApiDocument: {
1
+ export declare function buildOpenApiDocument(version: string): {
2
2
  readonly openapi: "3.1.0";
3
3
  readonly info: {
4
4
  readonly title: "Hooks Registry API";
5
- readonly version: "0.1.0";
5
+ readonly version: string;
6
6
  readonly description: "Local registry HTTP API for @hasna/hooks: catalog, lock, and artifact reads are open; publishing (PUT /api/v1/hooks) requires the API key (authorization: Bearer or x-api-key).";
7
7
  };
8
8
  readonly servers: readonly [{
@@ -19,8 +19,7 @@ export declare const openApiDocument: {
19
19
  readonly content: {
20
20
  readonly "application/json": {
21
21
  readonly schema: {
22
- readonly type: "object";
23
- readonly additionalProperties: true;
22
+ readonly $ref: "#/components/schemas/HooksHealth";
24
23
  };
25
24
  };
26
25
  };
@@ -35,9 +34,23 @@ export declare const openApiDocument: {
35
34
  readonly responses: {
36
35
  readonly "200": {
37
36
  readonly description: "Lock store is readable";
37
+ readonly content: {
38
+ readonly "application/json": {
39
+ readonly schema: {
40
+ readonly $ref: "#/components/schemas/HooksHealth";
41
+ };
42
+ };
43
+ };
38
44
  };
39
45
  readonly "503": {
40
46
  readonly description: "Lock store is not readable";
47
+ readonly content: {
48
+ readonly "application/json": {
49
+ readonly schema: {
50
+ readonly $ref: "#/components/schemas/HooksHealth";
51
+ };
52
+ };
53
+ };
41
54
  };
42
55
  };
43
56
  };
@@ -52,12 +65,7 @@ export declare const openApiDocument: {
52
65
  readonly content: {
53
66
  readonly "application/json": {
54
67
  readonly schema: {
55
- readonly type: "object";
56
- readonly properties: {
57
- readonly version: {
58
- readonly type: "string";
59
- };
60
- };
68
+ readonly $ref: "#/components/schemas/HooksVersion";
61
69
  };
62
70
  };
63
71
  };
@@ -72,6 +80,14 @@ export declare const openApiDocument: {
72
80
  readonly responses: {
73
81
  readonly "200": {
74
82
  readonly description: "OpenAPI 3.1 document";
83
+ readonly content: {
84
+ readonly "application/json": {
85
+ readonly schema: {
86
+ readonly type: "object";
87
+ readonly additionalProperties: true;
88
+ };
89
+ };
90
+ };
75
91
  };
76
92
  };
77
93
  };
@@ -86,32 +102,7 @@ export declare const openApiDocument: {
86
102
  readonly content: {
87
103
  readonly "application/json": {
88
104
  readonly schema: {
89
- readonly type: "object";
90
- readonly properties: {
91
- readonly hooks: {
92
- readonly type: "array";
93
- readonly items: {
94
- readonly type: "object";
95
- readonly properties: {
96
- readonly name: {
97
- readonly type: "string";
98
- };
99
- readonly version: {
100
- readonly type: "string";
101
- };
102
- readonly sha256: {
103
- readonly type: "string";
104
- };
105
- readonly events: {
106
- readonly type: "array";
107
- readonly items: {
108
- readonly type: "string";
109
- };
110
- };
111
- };
112
- };
113
- };
114
- };
105
+ readonly $ref: "#/components/schemas/HooksCatalog";
115
106
  };
116
107
  };
117
108
  };
@@ -126,6 +117,13 @@ export declare const openApiDocument: {
126
117
  readonly responses: {
127
118
  readonly "200": {
128
119
  readonly description: "The lock file";
120
+ readonly content: {
121
+ readonly "application/json": {
122
+ readonly schema: {
123
+ readonly $ref: "#/components/schemas/HooksLock";
124
+ };
125
+ };
126
+ };
129
127
  };
130
128
  };
131
129
  };
@@ -152,12 +150,41 @@ export declare const openApiDocument: {
152
150
  readonly responses: {
153
151
  readonly "200": {
154
152
  readonly description: "Hook artifact; x-hook-sha256 header carries the script hash";
153
+ readonly headers: {
154
+ readonly "x-hook-sha256": {
155
+ readonly description: "sha256 of the served script, the same value the lock pins";
156
+ readonly schema: {
157
+ readonly type: "string";
158
+ };
159
+ };
160
+ };
161
+ readonly content: {
162
+ readonly "application/json": {
163
+ readonly schema: {
164
+ readonly $ref: "#/components/schemas/HooksArtifact";
165
+ };
166
+ };
167
+ };
155
168
  };
156
169
  readonly "400": {
157
170
  readonly description: "Invalid URL encoding or semver version";
171
+ readonly content: {
172
+ readonly "application/json": {
173
+ readonly schema: {
174
+ readonly $ref: "#/components/schemas/HooksError";
175
+ };
176
+ };
177
+ };
158
178
  };
159
179
  readonly "404": {
160
180
  readonly description: "Hook not found locally";
181
+ readonly content: {
182
+ readonly "application/json": {
183
+ readonly schema: {
184
+ readonly $ref: "#/components/schemas/HooksError";
185
+ };
186
+ };
187
+ };
161
188
  };
162
189
  };
163
190
  };
@@ -171,15 +198,7 @@ export declare const openApiDocument: {
171
198
  readonly content: {
172
199
  readonly "application/json": {
173
200
  readonly schema: {
174
- readonly type: "object";
175
- readonly properties: {
176
- readonly name: {
177
- readonly type: "string";
178
- };
179
- readonly version: {
180
- readonly type: "string";
181
- };
182
- };
201
+ readonly $ref: "#/components/schemas/HooksPublishRequest";
183
202
  };
184
203
  };
185
204
  };
@@ -187,15 +206,53 @@ export declare const openApiDocument: {
187
206
  readonly responses: {
188
207
  readonly "200": {
189
208
  readonly description: "Hook retrusted and pin updated";
209
+ readonly content: {
210
+ readonly "application/json": {
211
+ readonly schema: {
212
+ readonly $ref: "#/components/schemas/HooksPublishResponse";
213
+ };
214
+ };
215
+ };
216
+ };
217
+ readonly "400": {
218
+ readonly description: "Invalid JSON body";
219
+ readonly content: {
220
+ readonly "application/json": {
221
+ readonly schema: {
222
+ readonly $ref: "#/components/schemas/HooksError";
223
+ };
224
+ };
225
+ };
190
226
  };
191
227
  readonly "401": {
192
228
  readonly description: "Missing or invalid API key";
229
+ readonly content: {
230
+ readonly "application/json": {
231
+ readonly schema: {
232
+ readonly $ref: "#/components/schemas/HooksError";
233
+ };
234
+ };
235
+ };
193
236
  };
194
237
  readonly "404": {
195
238
  readonly description: "Hook not found in local store";
239
+ readonly content: {
240
+ readonly "application/json": {
241
+ readonly schema: {
242
+ readonly $ref: "#/components/schemas/HooksError";
243
+ };
244
+ };
245
+ };
196
246
  };
197
247
  readonly "409": {
198
248
  readonly description: "Version mismatch with the local store";
249
+ readonly content: {
250
+ readonly "application/json": {
251
+ readonly schema: {
252
+ readonly $ref: "#/components/schemas/HooksError";
253
+ };
254
+ };
255
+ };
199
256
  };
200
257
  };
201
258
  readonly security: readonly [{
@@ -212,5 +269,217 @@ export declare const openApiDocument: {
212
269
  readonly description: "The registry API key — resolved by the client through the @hasna/contracts chain (HASNA_HOOKS_API_KEY, the Keychain item hasna.credentials.hooks.api-key, or ~/.hasna/hooks/config/credentials); the server compares the inbound bearer/x-api-key value.";
213
270
  };
214
271
  };
272
+ readonly schemas: {
273
+ readonly HooksHealth: {
274
+ readonly type: "object";
275
+ readonly additionalProperties: false;
276
+ readonly required: readonly ["status", "name"];
277
+ readonly properties: {
278
+ readonly status: {
279
+ readonly type: "string";
280
+ };
281
+ readonly name: {
282
+ readonly type: "string";
283
+ };
284
+ };
285
+ };
286
+ readonly HooksVersion: {
287
+ readonly type: "object";
288
+ readonly additionalProperties: false;
289
+ readonly required: readonly ["version"];
290
+ readonly properties: {
291
+ readonly version: {
292
+ readonly type: "string";
293
+ };
294
+ };
295
+ };
296
+ readonly HooksCatalogEntry: {
297
+ readonly type: "object";
298
+ readonly additionalProperties: false;
299
+ readonly required: readonly ["name", "version", "sha256", "events", "description", "source", "versions"];
300
+ readonly properties: {
301
+ readonly name: {
302
+ readonly type: "string";
303
+ };
304
+ readonly version: {
305
+ readonly type: "string";
306
+ };
307
+ readonly sha256: {
308
+ readonly type: "string";
309
+ };
310
+ readonly events: {
311
+ readonly type: "array";
312
+ readonly items: {
313
+ readonly type: "string";
314
+ };
315
+ };
316
+ readonly description: {
317
+ readonly type: "string";
318
+ };
319
+ readonly source: {
320
+ readonly type: "string";
321
+ readonly description: "bundled | custom | custom-overrides-bundled";
322
+ };
323
+ readonly versions: {
324
+ readonly type: "array";
325
+ readonly items: {
326
+ readonly type: "string";
327
+ };
328
+ };
329
+ };
330
+ };
331
+ readonly HooksCatalog: {
332
+ readonly type: "object";
333
+ readonly additionalProperties: false;
334
+ readonly required: readonly ["hooks"];
335
+ readonly properties: {
336
+ readonly hooks: {
337
+ readonly type: "array";
338
+ readonly items: {
339
+ readonly $ref: "#/components/schemas/HooksCatalogEntry";
340
+ };
341
+ };
342
+ };
343
+ };
344
+ readonly HooksLockEntry: {
345
+ readonly type: "object";
346
+ readonly additionalProperties: false;
347
+ readonly required: readonly ["version", "sha256", "source"];
348
+ readonly properties: {
349
+ readonly version: {
350
+ readonly type: "string";
351
+ };
352
+ readonly sha256: {
353
+ readonly type: "string";
354
+ };
355
+ readonly source: {
356
+ readonly type: "string";
357
+ };
358
+ readonly pinned: {
359
+ readonly type: "boolean";
360
+ readonly description: "True for an explicit install/update pin, absent for sync-maintained pins.";
361
+ };
362
+ readonly versions: {
363
+ readonly type: "array";
364
+ readonly items: {
365
+ readonly type: "string";
366
+ };
367
+ };
368
+ };
369
+ };
370
+ readonly HooksLock: {
371
+ readonly type: "object";
372
+ readonly additionalProperties: false;
373
+ readonly required: readonly ["hooks"];
374
+ readonly properties: {
375
+ readonly hooks: {
376
+ readonly type: "object";
377
+ readonly additionalProperties: {
378
+ readonly $ref: "#/components/schemas/HooksLockEntry";
379
+ };
380
+ };
381
+ };
382
+ };
383
+ readonly HooksManifest: {
384
+ readonly type: "object";
385
+ readonly additionalProperties: false;
386
+ readonly required: readonly ["name", "version", "events", "script"];
387
+ readonly properties: {
388
+ readonly name: {
389
+ readonly type: "string";
390
+ };
391
+ readonly version: {
392
+ readonly type: "string";
393
+ };
394
+ readonly description: {
395
+ readonly type: "string";
396
+ };
397
+ readonly events: {
398
+ readonly type: "array";
399
+ readonly items: {
400
+ readonly type: "string";
401
+ };
402
+ };
403
+ readonly script: {
404
+ readonly type: "string";
405
+ };
406
+ readonly script_kind: {
407
+ readonly type: "string";
408
+ readonly enum: readonly ["inline", "file"];
409
+ };
410
+ readonly args: {
411
+ readonly type: "array";
412
+ readonly items: {
413
+ readonly type: "string";
414
+ };
415
+ };
416
+ readonly timeout_ms: {
417
+ readonly type: "number";
418
+ };
419
+ };
420
+ };
421
+ readonly HooksArtifact: {
422
+ readonly type: "object";
423
+ readonly additionalProperties: false;
424
+ readonly required: readonly ["manifest", "script"];
425
+ readonly properties: {
426
+ readonly manifest: {
427
+ readonly $ref: "#/components/schemas/HooksManifest";
428
+ };
429
+ readonly script: {
430
+ readonly type: "string";
431
+ };
432
+ };
433
+ };
434
+ readonly HooksError: {
435
+ readonly type: "object";
436
+ readonly additionalProperties: false;
437
+ readonly required: readonly ["error"];
438
+ readonly properties: {
439
+ readonly error: {
440
+ readonly type: "string";
441
+ };
442
+ };
443
+ };
444
+ readonly HooksPublishRequest: {
445
+ readonly type: "object";
446
+ readonly additionalProperties: false;
447
+ readonly required: readonly ["name"];
448
+ readonly properties: {
449
+ readonly name: {
450
+ readonly type: "string";
451
+ };
452
+ readonly version: {
453
+ readonly type: "string";
454
+ };
455
+ };
456
+ };
457
+ readonly HooksPublishResponse: {
458
+ readonly type: "object";
459
+ readonly additionalProperties: false;
460
+ readonly required: readonly ["ok", "hook"];
461
+ readonly properties: {
462
+ readonly ok: {
463
+ readonly type: "boolean";
464
+ };
465
+ readonly hook: {
466
+ readonly type: "object";
467
+ readonly additionalProperties: false;
468
+ readonly required: readonly ["name", "version", "sha256"];
469
+ readonly properties: {
470
+ readonly name: {
471
+ readonly type: "string";
472
+ };
473
+ readonly version: {
474
+ readonly type: "string";
475
+ };
476
+ readonly sha256: {
477
+ readonly type: "string";
478
+ };
479
+ };
480
+ };
481
+ };
482
+ };
483
+ };
215
484
  };
216
485
  };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `@hasna/hooks/sdk` — the ONE hosted-authority resolver for this surface.
3
+ *
4
+ * Split out of `./index.ts` so the generated registry client's resolver-backed
5
+ * factory (`./registry-client.ts`) can share it without importing the module it
6
+ * is re-exported from (a module cycle between two SDK entry points).
7
+ *
8
+ * FAIL CLOSED (hasna/apps#1720): resolution goes through the ONE
9
+ * `@hasna/contracts` chain, as a strict URL+key pair, fresh on every call. With
10
+ * nothing resolved this THROWS the `REMOTE_API_*` diagnostic naming the tiers
11
+ * and the opt-in; it never returns an authority that would answer from a local
12
+ * file. The explicit local opt-in (`HASNA_HOOKS_LOCAL=1`, alias `HOOKS_LOCAL=1`)
13
+ * is refused here by name: the SDK is a hosted client and the on-box store is
14
+ * the CLI's, opt-in only.
15
+ */
16
+ import { type HooksRemoteAuthority, type HooksTransportOptions } from "../lib/transport.js";
17
+ import type { HooksCredentialOptions, HooksLocalOptInEnv } from "../lib/resolver-types.js";
18
+ export interface HooksClientOptions {
19
+ /** Injectable environment (tests). Defaults to `process.env`. */
20
+ env?: HooksLocalOptInEnv;
21
+ /** Tier-1 credential inputs and the injectable `security` runner. */
22
+ credentials?: HooksCredentialOptions;
23
+ /** Injectable fetch (tests). Defaults to the global `fetch`. */
24
+ fetch?: typeof fetch;
25
+ }
26
+ /**
27
+ * Resolve the hosted authority the SDK will talk to. Throws — never returns a
28
+ * local fallback — when nothing resolves, and refuses the local opt-in by
29
+ * name: there is no SDK surface for the on-box store.
30
+ */
31
+ export declare function resolveHooksSdkAuthority(env?: HooksLocalOptInEnv, options?: Omit<HooksTransportOptions, "notice">): HooksRemoteAuthority;
@@ -0,0 +1,97 @@
1
+ export interface HooksHealth {
2
+ "status": string;
3
+ "name": string;
4
+ }
5
+ export interface HooksVersion {
6
+ "version": string;
7
+ }
8
+ export interface HooksCatalogEntry {
9
+ "name": string;
10
+ "version": string;
11
+ "sha256": string;
12
+ "events": Array<string>;
13
+ "description": string;
14
+ "source": string;
15
+ "versions": Array<string>;
16
+ }
17
+ export interface HooksCatalog {
18
+ "hooks": Array<HooksCatalogEntry>;
19
+ }
20
+ export interface HooksLockEntry {
21
+ "version": string;
22
+ "sha256": string;
23
+ "source": string;
24
+ "pinned"?: boolean;
25
+ "versions"?: Array<string>;
26
+ }
27
+ export interface HooksLock {
28
+ "hooks": Record<string, HooksLockEntry>;
29
+ }
30
+ export interface HooksManifest {
31
+ "name": string;
32
+ "version": string;
33
+ "description"?: string;
34
+ "events": Array<string>;
35
+ "script": string;
36
+ "script_kind"?: "inline" | "file";
37
+ "args"?: Array<string>;
38
+ "timeout_ms"?: number;
39
+ }
40
+ export interface HooksArtifact {
41
+ "manifest": HooksManifest;
42
+ "script": string;
43
+ }
44
+ export interface HooksError {
45
+ "error": string;
46
+ }
47
+ export interface HooksPublishRequest {
48
+ "name": string;
49
+ "version"?: string;
50
+ }
51
+ export interface HooksPublishResponse {
52
+ "ok": boolean;
53
+ "hook": {
54
+ "name": string;
55
+ "version": string;
56
+ "sha256": string;
57
+ };
58
+ }
59
+ export interface HooksRegistryApiClientOptions {
60
+ /** Base URL, e.g. process.env.APP_API_URL. */
61
+ baseUrl: string;
62
+ /** API key, e.g. process.env.APP_API_KEY. Sent as the 'x-api-key' header. */
63
+ apiKey?: string;
64
+ /** Custom fetch (defaults to global fetch). */
65
+ fetch?: typeof fetch;
66
+ /** Extra headers merged into every request. */
67
+ headers?: Record<string, string>;
68
+ }
69
+ export declare class ApiError extends Error {
70
+ readonly status: number;
71
+ readonly body: unknown;
72
+ constructor(status: number, message: string, body: unknown);
73
+ }
74
+ export declare class HooksRegistryApiClient {
75
+ private readonly baseUrl;
76
+ private readonly apiKey;
77
+ private readonly fetchImpl;
78
+ private readonly baseHeaders;
79
+ constructor(options: HooksRegistryApiClientOptions);
80
+ private request;
81
+ /** List the full hook catalog with versions and sha256 */
82
+ getCatalog(init?: RequestInit): Promise<HooksCatalog>;
83
+ /** Publish/retrust a hook (requires the API key) */
84
+ putHook(body: HooksPublishRequest, init?: RequestInit): Promise<HooksPublishResponse>;
85
+ /** Fetch one hook's manifest and script */
86
+ getHookArtifact(name: string, version: string, init?: RequestInit): Promise<HooksArtifact>;
87
+ /** Read the published hooks.lock with per-hook versions */
88
+ getLock(init?: RequestInit): Promise<HooksLock>;
89
+ /** Liveness probe */
90
+ getHealth(init?: RequestInit): Promise<HooksHealth>;
91
+ /** This OpenAPI document */
92
+ getOpenApi(init?: RequestInit): Promise<Record<string, unknown>>;
93
+ /** Readiness probe — the hooks.lock store is readable */
94
+ getReady(init?: RequestInit): Promise<HooksHealth>;
95
+ /** Package version */
96
+ getVersion(init?: RequestInit): Promise<HooksVersion>;
97
+ }
@@ -16,10 +16,17 @@
16
16
  * opt-in (`HASNA_HOOKS_LOCAL=1`) is refused here by name: the SDK is a hosted
17
17
  * client and the on-box store is the CLI's, opt-in only.
18
18
  */
19
- import { hooksRegistryOrigin, type HooksRemoteAuthority, type HooksTransportOptions } from "../lib/transport.js";
19
+ import { hooksRegistryOrigin, type HooksRemoteAuthority } from "../lib/transport.js";
20
20
  import type { HooksCredentialOptions, HooksLocalOptInEnv } from "../lib/resolver-types.js";
21
+ import { type HooksClientOptions } from "./authority.js";
21
22
  export type { HooksRemoteAuthority, HooksCredentialOptions, HooksLocalOptInEnv };
22
23
  export { hooksRegistryOrigin };
24
+ export { resolveHooksSdkAuthority } from "./authority.js";
25
+ export type { HooksClientOptions } from "./authority.js";
26
+ export { HooksRegistryApiClient, ApiError as HooksRegistryApiError } from "./generated.js";
27
+ export type { HooksRegistryApiClientOptions, HooksHealth, HooksVersion, HooksCatalogEntry, HooksCatalog, HooksLockEntry, HooksLock, HooksManifest, HooksArtifact, HooksError, HooksPublishRequest, HooksPublishResponse, } from "./generated.js";
28
+ export { createHooksRegistryApiClient, hooksRegistryApiClientFor, } from "./registry-client.js";
29
+ export type { HooksRegistryApiClientAuthority, ResolvedHooksRegistryApiClient, } from "./registry-client.js";
23
30
  /** One row of `GET /api/v1/catalog` — the registry's latest version of a hook. */
24
31
  export interface HooksRegistryCatalogEntry {
25
32
  name: string;
@@ -56,23 +63,15 @@ export interface HooksRegistryArtifact {
56
63
  /** The registry's `x-hook-sha256` header for the served row, when present. */
57
64
  sha256: string | null;
58
65
  }
59
- export interface HooksClientOptions {
60
- /** Injectable environment (tests). Defaults to `process.env`. */
61
- env?: HooksLocalOptInEnv;
62
- /** Tier-1 credential inputs and the injectable `security` runner. */
63
- credentials?: HooksCredentialOptions;
64
- /** Injectable fetch (tests). Defaults to the global `fetch`. */
65
- fetch?: typeof fetch;
66
- }
67
- /**
68
- * Resolve the hosted authority the SDK will talk to. Throws — never returns a
69
- * local fallback — when nothing resolves, and refuses the local opt-in by
70
- * name: there is no SDK surface for the on-box store.
71
- */
72
- export declare function resolveHooksSdkAuthority(env?: HooksLocalOptInEnv, options?: Omit<HooksTransportOptions, "notice">): HooksRemoteAuthority;
73
66
  /**
74
67
  * Hosted registry client. Holds the authority binding privately and resolves
75
68
  * its current credential for each request before dispatch to that authority.
69
+ *
70
+ * This is the hand-kept, stable surface: it pins the `REMOTE_API_*` error
71
+ * codes, the raw `x-hook-sha256` header on `artifact()`, and the
72
+ * never-follow-a-redirect rule. `HooksRegistryApiClient` (./generated.ts) is
73
+ * the generated counterpart over the same served routes; it is additive, not
74
+ * a replacement.
76
75
  */
77
76
  export declare class HooksClient {
78
77
  #private;