hikoutei 0.10.10-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.
- package/README.ja.md +9 -9
- package/README.ko.md +9 -9
- package/README.md +15 -12
- package/dist/auth/serviceAccountAuthPool.d.ts +72 -0
- package/dist/auth/serviceAccountAuthPool.d.ts.map +1 -0
- package/dist/auth/serviceAccountAuthPool.js +92 -0
- package/dist/auth/serviceAccountAuthPool.js.map +1 -0
- package/dist/auth/serviceAccountKey.d.ts +85 -0
- package/dist/auth/serviceAccountKey.d.ts.map +1 -0
- package/dist/auth/serviceAccountKey.js +104 -0
- package/dist/auth/serviceAccountKey.js.map +1 -0
- package/dist/sheets/providers/google-sheets-api/transport/googleSheetsApiTransport.js +1 -1
- package/dist/sync-engine/sync/service/syncAutoStart.js +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -12,7 +12,7 @@ Google Sheets を利用する MVP 向けの型付きリポジトリであり、
|
|
|
12
12
|
Sheets へ非同期で投影されます。
|
|
13
13
|
|
|
14
14
|
<a href="https://www.npmjs.com/package/hikoutei">npm</a> ·
|
|
15
|
-
<a href="
|
|
15
|
+
<a href="website/guide/quick-start.md">クイックスタート</a> ·
|
|
16
16
|
<a href="https://github.com/ManddarinShop/Hikoutei/issues">Issues</a>
|
|
17
17
|
|
|
18
18
|
[](https://www.npmjs.com/package/hikoutei)
|
|
@@ -176,12 +176,12 @@ Hikoutei は、永続的なローカル outbox・冪等な配信・競合を考
|
|
|
176
176
|
ため、一時的な API 障害でコミット済みのアプリケーション書き込みが失われる
|
|
177
177
|
ことはありません。provider は資格情報・スプレッドシート ID・URL・ペイロードを
|
|
178
178
|
ログに残さず、Google の割り当て枠に収まるようリクエスト開始間隔を調整します。
|
|
179
|
-
詳細な状態機械と復旧ルールは[内部整合性モデル](
|
|
179
|
+
詳細な状態機械と復旧ルールは[内部整合性モデル](website/guide/internal-consistency.md)を
|
|
180
180
|
参照してください。
|
|
181
181
|
|
|
182
182
|
ライブの Google 呼び出しはオプトインであり、通常の検証経路はフェイク
|
|
183
183
|
provider と SQLite フィクスチャです。詳細なセットアップとトラブルシューティン
|
|
184
|
-
グは[クイックスタート](
|
|
184
|
+
グは[クイックスタート](website/guide/quick-start.md)を参照してください。
|
|
185
185
|
|
|
186
186
|
## インストール
|
|
187
187
|
|
|
@@ -196,15 +196,15 @@ MikroORM は実装の詳細であり、Hikoutei の公開エンティティ API
|
|
|
196
196
|
|
|
197
197
|
## ドキュメント
|
|
198
198
|
|
|
199
|
-
- [クイックスタート](
|
|
199
|
+
- [クイックスタート](website/guide/quick-start.md) — インストール、ORM ライフサイクル、
|
|
200
200
|
サービス側の同期設定
|
|
201
|
-
- [アーキテクチャ](
|
|
202
|
-
- [書き込みと同期フロー](
|
|
201
|
+
- [アーキテクチャ](website/guide/architecture.md) — ローカルストアとシートビューの関係
|
|
202
|
+
- [書き込みと同期フロー](website/guide/sync-flow.md) — 非同期配信と
|
|
203
203
|
復旧動作
|
|
204
|
-
- [内部整合性モデル](
|
|
204
|
+
- [内部整合性モデル](website/guide/internal-consistency.md) — 永続的な outbox、
|
|
205
205
|
冪等な配信、競合を考慮した更新
|
|
206
|
-
- [開発](
|
|
207
|
-
- [ベンチマークノート](
|
|
206
|
+
- [開発](website/guide/contributing.md) — ローカル開発とテストコマンド
|
|
207
|
+
- [ベンチマークノート](website/guide/benchmarks.md) — 日付付きの測定と
|
|
208
208
|
その限界
|
|
209
209
|
|
|
210
210
|
## 制限事項
|
package/README.ko.md
CHANGED
|
@@ -11,7 +11,7 @@ Google Sheets 기반 MVP를 위한 타입 안전 리포지토리이자 안전한
|
|
|
11
11
|
사람이 검토하고 가볍게 협업할 수 있도록 Google Sheets에 비동기로 투영됩니다.
|
|
12
12
|
|
|
13
13
|
<a href="https://www.npmjs.com/package/hikoutei">npm</a> ·
|
|
14
|
-
<a href="
|
|
14
|
+
<a href="website/guide/quick-start.md">빠른 시작</a> ·
|
|
15
15
|
<a href="https://github.com/ManddarinShop/Hikoutei/issues">이슈</a>
|
|
16
16
|
|
|
17
17
|
[](https://www.npmjs.com/package/hikoutei)
|
|
@@ -169,11 +169,11 @@ Hikoutei는 내구성 있는 로컬 outbox, 멱등 전달, 충돌을 인지하
|
|
|
169
169
|
사용하므로 일시적인 API 실패가 커밋된 애플리케이션 쓰기를 잃게 하지 않습니다.
|
|
170
170
|
provider는 자격 증명, 스프레드시트 ID, URL, 페이로드를 로그에 남기지 않으며,
|
|
171
171
|
Google 할당량 창 안에 머물도록 요청 시작 간격을 조절합니다. 상세 상태 머신과
|
|
172
|
-
복구 규칙은 [내부 정합성 모델](
|
|
172
|
+
복구 규칙은 [내부 정합성 모델](website/guide/internal-consistency.md)을
|
|
173
173
|
참고하세요.
|
|
174
174
|
|
|
175
175
|
라이브 Google 호출은 opt-in이며, 일반적인 검증 경로는 fake provider와 SQLite
|
|
176
|
-
fixture입니다. 자세한 설정과 문제 해결 단계는 [빠른 시작](
|
|
176
|
+
fixture입니다. 자세한 설정과 문제 해결 단계는 [빠른 시작](website/guide/quick-start.md)을
|
|
177
177
|
참고하세요.
|
|
178
178
|
|
|
179
179
|
## 설치
|
|
@@ -190,14 +190,14 @@ MikroORM은 구현 세부 사항이며 Hikoutei의 공개 엔티티 API에는
|
|
|
190
190
|
|
|
191
191
|
## 문서
|
|
192
192
|
|
|
193
|
-
- [빠른 시작](
|
|
194
|
-
- [아키텍처](
|
|
195
|
-
- [쓰기 및 동기화 흐름](
|
|
193
|
+
- [빠른 시작](website/guide/quick-start.md) — 설치, ORM 생명주기, 서비스 측 동기화 설정
|
|
194
|
+
- [아키텍처](website/guide/architecture.md) — 로컬 저장소와 Sheet 화면이 맞물리는 방식
|
|
195
|
+
- [쓰기 및 동기화 흐름](website/guide/sync-flow.md) — 비동기 전달과
|
|
196
196
|
복구 동작
|
|
197
|
-
- [내부 정합성 모델](
|
|
197
|
+
- [내부 정합성 모델](website/guide/internal-consistency.md) — 내구성 outbox,
|
|
198
198
|
멱등 전달, 충돌을 인지하는 업데이트
|
|
199
|
-
- [개발](
|
|
200
|
-
- [벤치마크 노트](
|
|
199
|
+
- [개발](website/guide/contributing.md) — 로컬 개발 및 테스트 명령어
|
|
200
|
+
- [벤치마크 노트](website/guide/benchmarks.md) — 날짜가 기록된 측정과
|
|
201
201
|
그 한계
|
|
202
202
|
|
|
203
203
|
## 한계
|
package/README.md
CHANGED
|
@@ -123,11 +123,14 @@ client directly.
|
|
|
123
123
|
|
|
124
124
|
Google Sheets synchronization is a service-side concern. Applications do not
|
|
125
125
|
import a provider client, pass Sheet routes to `createTypedSheets()`, or choose
|
|
126
|
-
an operation for each write —
|
|
127
|
-
`entities
|
|
128
|
-
a service account — no Apps Script
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
an operation for each write — `CreateTypedSheetsOptions` fields (`dbName`,
|
|
127
|
+
`entities`, `providerOptions`) are all optional. The sync runtime uses one
|
|
128
|
+
internal Google Sheets API provider with a service account — no Apps Script
|
|
129
|
+
deployment. Sync auto-start is selected by `HIKOUTEI_SYNC_SPREADSHEET_URL`
|
|
130
|
+
plus `GOOGLE_APPLICATION_CREDENTIALS`. Optional `providerOptions` tunes the
|
|
131
|
+
sync-path provider (telemetry/timeouts; inert when local-only), and
|
|
132
|
+
`createTypedSheetsWithSync()` exposes the same options with a richer result
|
|
133
|
+
for existing-sheet adoption.
|
|
131
134
|
|
|
132
135
|
**Fastest path:** install the gcloud CLI, then run `npx hikoutei setup` from your
|
|
133
136
|
project directory. On an interactive terminal it offers (press Enter) to
|
|
@@ -247,8 +250,8 @@ shared on the spreadsheet (the error tells you which email to share).
|
|
|
247
250
|
`GOOGLE_APPLICATION_CREDENTIALS` and `HIKOUTEI_SYNC_SPREADSHEET_URL` set;
|
|
248
251
|
`createTypedSheets()` detects them and starts the internal sync bootstrap —
|
|
249
252
|
it creates and verifies headers on the registered tabs, then starts outbox
|
|
250
|
-
delivery and User_Input polling.
|
|
251
|
-
internal bootstrap to start by hand.
|
|
253
|
+
delivery and User_Input polling. Pass `providerOptions` only when sync-path
|
|
254
|
+
tuning is needed; there is no internal bootstrap to start by hand.
|
|
252
255
|
|
|
253
256
|
> **Legacy spreadsheet note.** Spreadsheets provisioned by the old Apps Script
|
|
254
257
|
> provider with developer-metadata row anchors are not migrated: `User_Input`
|
|
@@ -273,15 +276,15 @@ verification path. The detailed setup and troubleshooting steps are in the
|
|
|
273
276
|
|
|
274
277
|
## Installation
|
|
275
278
|
|
|
276
|
-
The project and npm package are both called `hikoutei`.
|
|
277
|
-
|
|
279
|
+
The project and npm package are both called `hikoutei`. This repo uses pnpm
|
|
280
|
+
(packageManager `pnpm@11.1.2`):
|
|
278
281
|
|
|
279
282
|
```sh
|
|
280
|
-
|
|
283
|
+
pnpm install --frozen-lockfile
|
|
281
284
|
```
|
|
282
285
|
|
|
283
|
-
|
|
284
|
-
|
|
286
|
+
`@mikro-orm/core` and `@mikro-orm/sql` are optional peers (`optional: true`),
|
|
287
|
+
lazy-loaded only when a runtime opens. `npm install` still works for consumers.
|
|
285
288
|
|
|
286
289
|
## Documentation
|
|
287
290
|
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,kGAAkG;AAClG,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,CAAU,CAAC;AAwCzG;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,GAAW,EACX,IAAY,EACZ,OAAqC;IAErC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,MAAM,GAAG,MAAiC,CAAC;IACjD,MAAM,aAAa,GAAG,0BAA0B,CAAC,MAAM,CACrD,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAK,MAAM,CAAC,KAAK,CAAY,CAAC,IAAI,EAAE,KAAK,EAAE,CACxF,CAAC;IACF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,YAAsB,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAC3C,OAAe,EACf,OAAqC;IAErC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,0BAA0B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAe,EACf,OAAqC;IAErC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,0BAA0B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAoC,EACpC,MAAyB;IAEzB,OAAO,IAAI,UAAU,CAAC;QACpB,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;QACnB,WAAW;KAC8C,CAAC,CAAC;AAC/D,CAAC;AAED,0EAA0E;AAC1E,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,GAAI,KAAqC,CAAC,IAAI,CAAC;QACzD,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -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 "
|
|
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 "
|
|
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.
|
|
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",
|