hikoutei 0.10.11-dev → 0.10.13-dev

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,72 @@
1
+ /**
2
+ * Shared service-account credential-pool ownership (Batch A).
3
+ *
4
+ * This module owns the N-`GoogleAuth` pool every provider line paces and
5
+ * signs with: one auth per key file (one Google quota principal), the
6
+ * deterministic round-robin cursor, and the per-identity index binding that
7
+ * ties admission to transport (the admitted identity IS the signing
8
+ * identity). Providers build their API clients (`sheets({ version, auth })`
9
+ * stays provider-side) from the selected auths; the pacing pool
10
+ * (`CredentialPacingPool` in ikisaki) meets this pool at the existing
11
+ * admission→transport index binding, which is unchanged.
12
+ *
13
+ * Out-of-range selection fails CLOSED through the caller-supplied
14
+ * `onInvalidSelection` (same parameterization as the key loader's `fail`):
15
+ * signing with a different identity than the one admission paced against
16
+ * would silently defeat the per-identity quota contract.
17
+ */
18
+ import type { GoogleAuth } from "google-auth-library";
19
+ import { type ServiceAccountKeyLoadOptions } from "./serviceAccountKey.js";
20
+ /**
21
+ * Advances (and returns) the next round-robin client index for a pool.
22
+ *
23
+ * A preferred (provider-admitted) index is returned WITHOUT advancing the
24
+ * cursor, so admission-bound calls never skew the fallback rotation. The
25
+ * cursor is a mutable carrier so callers keep the rotation across requests;
26
+ * `clientCount` must be ≥ 1.
27
+ */
28
+ export declare function nextPooledClientIndex(cursor: {
29
+ next: number;
30
+ }, clientCount: number, preferredIndex: number | undefined): number;
31
+ /** Selection failure mapping (must throw, never return). */
32
+ export interface ServiceAccountAuthPoolSelection {
33
+ readonly onInvalidSelection: (message: string) => never;
34
+ }
35
+ /** Key-file pool construction: scopes plus both failure mappings. */
36
+ export interface ServiceAccountAuthPoolKeyFilesOptions extends ServiceAccountKeyLoadOptions, ServiceAccountAuthPoolSelection {
37
+ /** OAuth scopes the pooled auths request (provider-owned, e.g. Sheets/Drive). */
38
+ readonly scopes: readonly string[];
39
+ }
40
+ /**
41
+ * The N-`GoogleAuth` credential pool plus its rotation cursor.
42
+ *
43
+ * Generic over the auth value so providers wrap their own auth flavor
44
+ * (injected test auths, the ADC default) together with the file-backed
45
+ * `GoogleAuth` instances under ONE selection cursor.
46
+ */
47
+ export declare class ServiceAccountAuthPool<TAuth = GoogleAuth> {
48
+ /** Every pooled credential; index-aligned with the provider's clients. */
49
+ readonly auths: readonly TAuth[];
50
+ private readonly selection;
51
+ /** Fallback rotation cursor for requests WITHOUT an admitted index. */
52
+ private readonly poolCursor;
53
+ constructor(
54
+ /** Every pooled credential; index-aligned with the provider's clients. */
55
+ auths: readonly TAuth[], selection: ServiceAccountAuthPoolSelection);
56
+ /**
57
+ * Builds the file-backed pool: each key file is read and turned into its
58
+ * own `GoogleAuth` at construction (fail fast on unreadable or malformed
59
+ * files). Error payloads carry the PATH only — never file contents,
60
+ * client emails, or key material.
61
+ */
62
+ static loadFromKeyFiles(keyFiles: readonly string[], options: ServiceAccountAuthPoolKeyFilesOptions): ServiceAccountAuthPool<GoogleAuth>;
63
+ /** Number of pooled credentials (quota principals). */
64
+ get size(): number;
65
+ /**
66
+ * Picks the pool index for one request: the admitted identity when the
67
+ * request carries one, otherwise the next round-robin entry (a 1-auth
68
+ * pool always selects index 0 — the historical single-auth path).
69
+ */
70
+ selectIndex(preferredIndex: number | undefined): number;
71
+ }
72
+ //# sourceMappingURL=serviceAccountAuthPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceAccountAuthPool.d.ts","sourceRoot":"","sources":["../../../../../../../src/auth/serviceAccountAuthPool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAIL,KAAK,4BAA4B,EAClC,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACxB,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,MAAM,CAOR;AAED,4DAA4D;AAC5D,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC;CACzD;AAED,qEAAqE;AACrE,MAAM,WAAW,qCACf,SAAQ,4BAA4B,EAAE,+BAA+B;IACrE,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;GAMG;AACH,qBAAa,sBAAsB,CAAC,KAAK,GAAG,UAAU;IAKlD,0EAA0E;aAC1D,KAAK,EAAE,SAAS,KAAK,EAAE;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiC;;IAG1D,0EAA0E;IAC1D,KAAK,EAAE,SAAS,KAAK,EAAE,EACtB,SAAS,EAAE,+BAA+B;IAG7D;;;;;OAKG;WACW,gBAAgB,CAC5B,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,OAAO,EAAE,qCAAqC,GAC7C,sBAAsB,CAAC,UAAU,CAAC;IASrC,uDAAuD;IACvD,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;;;OAIG;IACI,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM;CAe/D"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared service-account credential-pool ownership (Batch A).
3
+ *
4
+ * This module owns the N-`GoogleAuth` pool every provider line paces and
5
+ * signs with: one auth per key file (one Google quota principal), the
6
+ * deterministic round-robin cursor, and the per-identity index binding that
7
+ * ties admission to transport (the admitted identity IS the signing
8
+ * identity). Providers build their API clients (`sheets({ version, auth })`
9
+ * stays provider-side) from the selected auths; the pacing pool
10
+ * (`CredentialPacingPool` in ikisaki) meets this pool at the existing
11
+ * admission→transport index binding, which is unchanged.
12
+ *
13
+ * Out-of-range selection fails CLOSED through the caller-supplied
14
+ * `onInvalidSelection` (same parameterization as the key loader's `fail`):
15
+ * signing with a different identity than the one admission paced against
16
+ * would silently defeat the per-identity quota contract.
17
+ */
18
+ import { createServiceAccountAuth, loadServiceAccountKeyFileSync, } from "./serviceAccountKey.js";
19
+ /**
20
+ * Advances (and returns) the next round-robin client index for a pool.
21
+ *
22
+ * A preferred (provider-admitted) index is returned WITHOUT advancing the
23
+ * cursor, so admission-bound calls never skew the fallback rotation. The
24
+ * cursor is a mutable carrier so callers keep the rotation across requests;
25
+ * `clientCount` must be ≥ 1.
26
+ */
27
+ export function nextPooledClientIndex(cursor, clientCount, preferredIndex) {
28
+ if (preferredIndex !== undefined) {
29
+ return preferredIndex;
30
+ }
31
+ const index = cursor.next % clientCount;
32
+ cursor.next = (index + 1) % clientCount;
33
+ return index;
34
+ }
35
+ /**
36
+ * The N-`GoogleAuth` credential pool plus its rotation cursor.
37
+ *
38
+ * Generic over the auth value so providers wrap their own auth flavor
39
+ * (injected test auths, the ADC default) together with the file-backed
40
+ * `GoogleAuth` instances under ONE selection cursor.
41
+ */
42
+ export class ServiceAccountAuthPool {
43
+ auths;
44
+ selection;
45
+ /** Fallback rotation cursor for requests WITHOUT an admitted index. */
46
+ poolCursor = { next: 0 };
47
+ constructor(
48
+ /** Every pooled credential; index-aligned with the provider's clients. */
49
+ auths, selection) {
50
+ this.auths = auths;
51
+ this.selection = selection;
52
+ }
53
+ /**
54
+ * Builds the file-backed pool: each key file is read and turned into its
55
+ * own `GoogleAuth` at construction (fail fast on unreadable or malformed
56
+ * files). Error payloads carry the PATH only — never file contents,
57
+ * client emails, or key material.
58
+ */
59
+ static loadFromKeyFiles(keyFiles, options) {
60
+ const fail = (failure) => options.fail(failure);
61
+ const auths = keyFiles.map((keyFile) => {
62
+ const { credentials } = loadServiceAccountKeyFileSync(keyFile, { fail });
63
+ return createServiceAccountAuth(credentials, options.scopes);
64
+ });
65
+ return new ServiceAccountAuthPool(auths, options);
66
+ }
67
+ /** Number of pooled credentials (quota principals). */
68
+ get size() {
69
+ return this.auths.length;
70
+ }
71
+ /**
72
+ * Picks the pool index for one request: the admitted identity when the
73
+ * request carries one, otherwise the next round-robin entry (a 1-auth
74
+ * pool always selects index 0 — the historical single-auth path).
75
+ */
76
+ selectIndex(preferredIndex) {
77
+ if (preferredIndex !== undefined) {
78
+ if (this.auths[preferredIndex] === undefined) {
79
+ // Fail CLOSED before any wire contact: signing with a different
80
+ // identity than the one admission paced against would silently
81
+ // defeat the per-identity quota contract.
82
+ this.selection.onInvalidSelection("credentialIndex is outside the client pool");
83
+ }
84
+ return preferredIndex;
85
+ }
86
+ if (this.auths.length === 1) {
87
+ return 0;
88
+ }
89
+ return nextPooledClientIndex(this.poolCursor, this.auths.length, undefined);
90
+ }
91
+ }
92
+ //# sourceMappingURL=serviceAccountAuthPool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceAccountAuthPool.js","sourceRoot":"","sources":["../../../../../../../src/auth/serviceAccountAuthPool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EACL,wBAAwB,EACxB,6BAA6B,GAG9B,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAwB,EACxB,WAAmB,EACnB,cAAkC;IAElC,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,WAAW,CAAC;IACxC,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;IACxC,OAAO,KAAK,CAAC;AACf,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,OAAO,sBAAsB;IAMf;IACC;IANnB,uEAAuE;IACtD,UAAU,GAAqB,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAE5D;IACE,0EAA0E;IAC1D,KAAuB,EACtB,SAA0C;QAD3C,UAAK,GAAL,KAAK,CAAkB;QACtB,cAAS,GAAT,SAAS,CAAiC;IAC1D,CAAC;IAEJ;;;;;OAKG;IACI,MAAM,CAAC,gBAAgB,CAC5B,QAA2B,EAC3B,OAA8C;QAE9C,MAAM,IAAI,GAAG,CAAC,OAAiC,EAAS,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjF,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACrC,MAAM,EAAE,WAAW,EAAE,GAAG,6BAA6B,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACzE,OAAO,wBAAwB,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,uDAAuD;IACvD,IAAW,IAAI;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACI,WAAW,CAAC,cAAkC;QACnD,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC7C,gEAAgE;gBAChE,+DAA+D;gBAC/D,0CAA0C;gBAC1C,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,4CAA4C,CAAC,CAAC;YAClF,CAAC;YACD,OAAO,cAAc,CAAC;QACxB,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO,qBAAqB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC9E,CAAC;CACF"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Shared service-account key-file loading + shape validation (Batch A).
3
+ *
4
+ * This is the ONE loader for Google service-account key files, reused by
5
+ * every provider line (Sheets today; Drive/Gmail next) and by the sync
6
+ * auto-start bridge. It reads, JSON-parses, and SHAPE-validates a key file
7
+ * so a misconfigured credential fails fast and locally — a malformed file
8
+ * must never build an auth client that only breaks on first signing.
9
+ *
10
+ * Neutral error contract: this leaf owns no provider vocabulary, so every
11
+ * failure is reported through the caller-supplied `fail` callback as a
12
+ * discriminated `ServiceAccountKeyFailure` (quotaGovernor `timingDefaults`
13
+ * precedent — behavior injected, dependency direction kept acyclic). The
14
+ * Sheets transport maps every kind to its transport error; the sync
15
+ * auto-start bridge maps them to the stable startup codes. Failure payloads
16
+ * carry the PATH (and field names) only — never file contents, client
17
+ * emails, or key material.
18
+ */
19
+ import { GoogleAuth } from "google-auth-library";
20
+ /** Required service-account key-file fields, checked by SHAPE (non-blank string) only at load. */
21
+ export declare const SERVICE_ACCOUNT_KEY_FIELDS: readonly ["type", "client_email", "private_key", "project_id"];
22
+ /** Structured key-file load failure (path-bearing only, never key material). */
23
+ export type ServiceAccountKeyFailure = {
24
+ /** The file could not be read (`code` is the Node errno, e.g. `ENOENT`). */
25
+ readonly kind: "read-error";
26
+ readonly path: string;
27
+ readonly code: string | undefined;
28
+ } | {
29
+ /** The file contents are not valid JSON. */
30
+ readonly kind: "invalid-json";
31
+ readonly path: string;
32
+ } | {
33
+ /** The file parsed but is not a JSON object. */
34
+ readonly kind: "not-object";
35
+ readonly path: string;
36
+ } | {
37
+ /** Required service-account fields are missing or blank (NAMES only, never values). */
38
+ readonly kind: "field-missing";
39
+ readonly path: string;
40
+ readonly fields: readonly string[];
41
+ };
42
+ /** Loader options: the caller's failure mapping (must throw, never return). */
43
+ export interface ServiceAccountKeyLoadOptions {
44
+ readonly fail: (failure: ServiceAccountKeyFailure) => never;
45
+ }
46
+ /** One validated service-account key: raw credentials plus the client email. */
47
+ export interface LoadedServiceAccountKey {
48
+ /** Parsed key JSON, passed straight into `GoogleAuth.credentials` (never logged). */
49
+ readonly credentials: Record<string, unknown>;
50
+ /** The `client_email` field (used for access-denied hints, never logged by this leaf). */
51
+ readonly clientEmail: string;
52
+ }
53
+ /**
54
+ * Validates parsed key JSON by SHAPE and promotes it to a loaded key.
55
+ *
56
+ * Shared by the sync/async file loaders so both paths enforce the identical
57
+ * contract: the payload must be a JSON object whose required
58
+ * service-account fields are non-blank strings. Without this, ANY JSON
59
+ * object builds a GoogleAuth client and the failure surfaces mid-run on
60
+ * first signing instead of at load.
61
+ */
62
+ export declare function parseServiceAccountKeyJson(raw: string, path: string, options: ServiceAccountKeyLoadOptions): LoadedServiceAccountKey;
63
+ /**
64
+ * Loads + validates one key file synchronously (transport construction path).
65
+ *
66
+ * Reads and shape-validates the file at construction so a misconfigured
67
+ * pool fails fast and locally. Failure messages carry the path only.
68
+ */
69
+ export declare function loadServiceAccountKeyFileSync(keyFile: string, options: ServiceAccountKeyLoadOptions): LoadedServiceAccountKey;
70
+ /**
71
+ * Loads + validates one key file asynchronously (startup-bridge path).
72
+ *
73
+ * Same contract as the sync loader; the bridge keeps its own env parsing
74
+ * and error-code mapping and delegates only file loading/validation here.
75
+ */
76
+ export declare function loadServiceAccountKeyFile(keyFile: string, options: ServiceAccountKeyLoadOptions): Promise<LoadedServiceAccountKey>;
77
+ /**
78
+ * Builds one pooled `GoogleAuth` from validated key credentials.
79
+ *
80
+ * The caller supplies the scopes (Sheets/Drive/Gmail each request their
81
+ * own); the cast keeps the google-auth-library version-shape mismatch
82
+ * inside this leaf, exactly like the former per-provider boundary casts.
83
+ */
84
+ export declare function createServiceAccountAuth(credentials: Record<string, unknown>, scopes: readonly string[]): GoogleAuth;
85
+ //# sourceMappingURL=serviceAccountKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceAccountKey.d.ts","sourceRoot":"","sources":["../../../../../../../src/auth/serviceAccountKey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAIjD,kGAAkG;AAClG,eAAO,MAAM,0BAA0B,gEAAiE,CAAC;AAEzG,gFAAgF;AAChF,MAAM,MAAM,wBAAwB,GAChC;IACE,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,GACD;IACE,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GACD;IACE,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GACD;IACE,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC,CAAC;AAEN,+EAA+E;AAC/E,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,KAAK,CAAC;CAC7D;AAED,gFAAgF;AAChF,MAAM,WAAW,uBAAuB;IACtC,qFAAqF;IACrF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,0FAA0F;IAC1F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,4BAA4B,GACpC,uBAAuB,CAkBzB;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,4BAA4B,GACpC,uBAAuB,CAQzB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,uBAAuB,CAAC,CAQlC;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,UAAU,CAKZ"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Shared service-account key-file loading + shape validation (Batch A).
3
+ *
4
+ * This is the ONE loader for Google service-account key files, reused by
5
+ * every provider line (Sheets today; Drive/Gmail next) and by the sync
6
+ * auto-start bridge. It reads, JSON-parses, and SHAPE-validates a key file
7
+ * so a misconfigured credential fails fast and locally — a malformed file
8
+ * must never build an auth client that only breaks on first signing.
9
+ *
10
+ * Neutral error contract: this leaf owns no provider vocabulary, so every
11
+ * failure is reported through the caller-supplied `fail` callback as a
12
+ * discriminated `ServiceAccountKeyFailure` (quotaGovernor `timingDefaults`
13
+ * precedent — behavior injected, dependency direction kept acyclic). The
14
+ * Sheets transport maps every kind to its transport error; the sync
15
+ * auto-start bridge maps them to the stable startup codes. Failure payloads
16
+ * carry the PATH (and field names) only — never file contents, client
17
+ * emails, or key material.
18
+ */
19
+ import { GoogleAuth } from "google-auth-library";
20
+ import { readFileSync } from "node:fs";
21
+ import { readFile } from "node:fs/promises";
22
+ /** Required service-account key-file fields, checked by SHAPE (non-blank string) only at load. */
23
+ export const SERVICE_ACCOUNT_KEY_FIELDS = ["type", "client_email", "private_key", "project_id"];
24
+ /**
25
+ * Validates parsed key JSON by SHAPE and promotes it to a loaded key.
26
+ *
27
+ * Shared by the sync/async file loaders so both paths enforce the identical
28
+ * contract: the payload must be a JSON object whose required
29
+ * service-account fields are non-blank strings. Without this, ANY JSON
30
+ * object builds a GoogleAuth client and the failure surfaces mid-run on
31
+ * first signing instead of at load.
32
+ */
33
+ export function parseServiceAccountKeyJson(raw, path, options) {
34
+ let parsed;
35
+ try {
36
+ parsed = JSON.parse(raw);
37
+ }
38
+ catch {
39
+ options.fail({ kind: "invalid-json", path });
40
+ }
41
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
42
+ options.fail({ kind: "not-object", path });
43
+ }
44
+ const record = parsed;
45
+ const invalidFields = SERVICE_ACCOUNT_KEY_FIELDS.filter((field) => typeof record[field] !== "string" || record[field].trim() === "");
46
+ if (invalidFields.length > 0) {
47
+ options.fail({ kind: "field-missing", path, fields: invalidFields });
48
+ }
49
+ return { credentials: record, clientEmail: record.client_email };
50
+ }
51
+ /**
52
+ * Loads + validates one key file synchronously (transport construction path).
53
+ *
54
+ * Reads and shape-validates the file at construction so a misconfigured
55
+ * pool fails fast and locally. Failure messages carry the path only.
56
+ */
57
+ export function loadServiceAccountKeyFileSync(keyFile, options) {
58
+ let raw;
59
+ try {
60
+ raw = readFileSync(keyFile, "utf8");
61
+ }
62
+ catch (error) {
63
+ options.fail({ kind: "read-error", path: keyFile, code: nodeErrorCode(error) });
64
+ }
65
+ return parseServiceAccountKeyJson(raw, keyFile, options);
66
+ }
67
+ /**
68
+ * Loads + validates one key file asynchronously (startup-bridge path).
69
+ *
70
+ * Same contract as the sync loader; the bridge keeps its own env parsing
71
+ * and error-code mapping and delegates only file loading/validation here.
72
+ */
73
+ export async function loadServiceAccountKeyFile(keyFile, options) {
74
+ let raw;
75
+ try {
76
+ raw = await readFile(keyFile, "utf8");
77
+ }
78
+ catch (error) {
79
+ options.fail({ kind: "read-error", path: keyFile, code: nodeErrorCode(error) });
80
+ }
81
+ return parseServiceAccountKeyJson(raw, keyFile, options);
82
+ }
83
+ /**
84
+ * Builds one pooled `GoogleAuth` from validated key credentials.
85
+ *
86
+ * The caller supplies the scopes (Sheets/Drive/Gmail each request their
87
+ * own); the cast keeps the google-auth-library version-shape mismatch
88
+ * inside this leaf, exactly like the former per-provider boundary casts.
89
+ */
90
+ export function createServiceAccountAuth(credentials, scopes) {
91
+ return new GoogleAuth({
92
+ scopes: [...scopes],
93
+ credentials,
94
+ });
95
+ }
96
+ /** Extracts the Node errno (`ENOENT`, ...) from a caught read failure. */
97
+ function nodeErrorCode(error) {
98
+ if (error !== null && typeof error === "object") {
99
+ const code = error.code;
100
+ return typeof code === "string" ? code : undefined;
101
+ }
102
+ return undefined;
103
+ }
104
+ //# sourceMappingURL=serviceAccountKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serviceAccountKey.js","sourceRoot":"","sources":["../../../../../../../src/auth/serviceAccountKey.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,7 @@ import { sheets } from "@googleapis/sheets";
13
13
  import { presentValue, absentValue, PRESENCE_KINDS } from "../../../../contracts/state/index.js";
14
14
  import { HIKOUTEI_LOG_LEVELS, logHikouteiInternalEvent, } from "../../../../contracts/shared/observability/internalLog.js";
15
15
  import { HIKOUTEI_LOG_COMPONENTS, HIKOUTEI_LOG_EVENTS, } from "../../../../contracts/shared/observability/logEvents.js";
16
- import { ServiceAccountAuthPool, } from "@hikoutei/google-auth/auth/serviceAccountAuthPool.js";
16
+ import { ServiceAccountAuthPool, } from "../../../../auth/serviceAccountAuthPool.js";
17
17
  import { GOOGLE_SHEETS_API_SCOPES } from "../constants.js";
18
18
  import { GOOGLE_SHEETS_API_TRANSPORT_ERROR_CODES, GoogleSheetsApiTransportError, invalidProviderRequest, } from "../errors.js";
19
19
  import { parseRawErrorRecord, parseRawErrorText, parseRawHttpStatus, } from "@hikoutei/ikisaki";
@@ -21,7 +21,7 @@
21
21
  * the diagnostic sink (console by default), and thrown fail-closed: a startup
22
22
  * failure never leaves a half-open runtime behind.
23
23
  */
24
- import { loadServiceAccountKeyFile } from "@hikoutei/google-auth/auth/serviceAccountKey.js";
24
+ import { loadServiceAccountKeyFile } from "../../../auth/serviceAccountKey.js";
25
25
  import { getEntityDescriptor, } from "../../api/entity.js";
26
26
  import { validateTypedSheetsOptions, } from "../../api/hikouteiCore.js";
27
27
  import { requireSyncEngineLocalRuntime } from "./compositionPorts.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hikoutei",
3
- "version": "0.10.11-dev",
3
+ "version": "0.10.13-dev",
4
4
  "description": "Typed repository and safe write layer for Google Sheets-backed MVPs. SQLite-authoritative entity lifecycle with asynchronous Google Sheets projection.",
5
5
  "repository": {
6
6
  "type": "git",