gik-service-providers 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -7,6 +7,7 @@ npm install gik-service-providers
7
7
  ```ts
8
8
  import { createSchedulerServiceKind } from "gik-service-providers/scheduler";
9
9
  import { createGmailServiceKind } from "gik-service-providers/gmail";
10
+ import { createGitHubContextStoreServiceKind } from "gik-service-providers/github-context-store";
10
11
  ```
11
12
 
12
13
  There is deliberately **no package-root export or index barrel**. Applications
@@ -126,9 +127,47 @@ HTTP 408/5xx, or an unreadable success response produces
126
127
  Investigate Sent mail and require fresh host authority before a new attempt;
127
128
  Gmail does not provide a general idempotent-send guarantee.
128
129
 
130
+ ## GitHub context store
131
+
132
+ Kind `github-context-store`, version `1`, implements the standard
133
+ `context-store.query/v1` and `context-store.ingest/v1` contracts:
134
+
135
+ ```json
136
+ {
137
+ "endpoint": "https://api.github.com",
138
+ "repository": "owner/private-backing-store",
139
+ "ref": "refs/heads/context-v1",
140
+ "prefix": ".gik-state/context/v1",
141
+ "credentialRef": "github/context-store",
142
+ "maxRecordsPerScope": 1000,
143
+ "maxWriteAttempts": 3
144
+ }
145
+ ```
146
+
147
+ The configured ref must already exist. The provider never creates repositories,
148
+ refs, credentials or authorization. The host resolves `credentialRef` to a
149
+ `GitHubContextStoreConnection` that adds authentication internally, and must
150
+ authorize every concrete `https://api.github.com` URL before the provider asks
151
+ for that connection. Query-only declarations require GitHub Contents read
152
+ permission; a declaration containing ingest requires Contents write permission.
153
+
154
+ Scopes and record identities are SHA-256 encoded into repository paths.
155
+ Ingestion creates immutable record blobs and a bounded recent-record index in
156
+ one Git commit, then advances the declared ref without force. Reusing an
157
+ identity with different content fails. A non-fast-forward ref race is rebuilt
158
+ from the new head up to `maxWriteAttempts`; exhaustion is explicit. Query reads
159
+ one ref revision and returns at most the requested standard limit. The Git
160
+ revision used or created is returned in `ServiceExecutionResult.detail`, while
161
+ the standard context-store output shape remains unchanged.
162
+
163
+ This provider stores only bounded, non-sensitive context. It is not a token
164
+ vault, GitHub event archive, durable-runtime journal, or substitute for host
165
+ authorization. Actions artifacts and Copilot Memory have different retention
166
+ and consistency semantics and are not silently used as fallbacks.
167
+
129
168
  ## Distribution and release
130
169
 
131
- Both subpaths are independently built and smoke-tested from the actual npm
170
+ All subpaths are independently built and smoke-tested from the actual npm
132
171
  tarball in a clean consumer, including TypeScript and the absent root export.
133
172
  GitHub Actions performs all installation, build, typecheck and tests for this
134
173
  repository. Publishing remains a protected maintainer-approved action; see the
@@ -0,0 +1,26 @@
1
+ import { ServiceKindFactory } from 'gik-controlface/services';
2
+
3
+ interface GitHubContextStoreHttpRequest {
4
+ url: string;
5
+ method: "GET" | "POST" | "PATCH";
6
+ headers: Readonly<Record<string, string>>;
7
+ body?: string;
8
+ signal: AbortSignal;
9
+ }
10
+ /** The host owns authentication and adds it inside this connection. */
11
+ interface GitHubContextStoreConnection {
12
+ request(request: Readonly<GitHubContextStoreHttpRequest>): Promise<Response>;
13
+ }
14
+ declare class GitHubContextRecordConflictError extends Error {
15
+ readonly code = "github-context-record-conflict";
16
+ constructor(recordId: string);
17
+ }
18
+ declare class GitHubContextStoreRevisionConflictError extends Error {
19
+ readonly ref: string;
20
+ readonly attempts: number;
21
+ readonly code = "github-context-store-revision-conflict";
22
+ constructor(ref: string, attempts: number);
23
+ }
24
+ declare function createGitHubContextStoreServiceKind(): ServiceKindFactory;
25
+
26
+ export { GitHubContextRecordConflictError, type GitHubContextStoreConnection, type GitHubContextStoreHttpRequest, GitHubContextStoreRevisionConflictError, createGitHubContextStoreServiceKind };
@@ -0,0 +1,647 @@
1
+ // src/github-context-store.ts
2
+ import { createHash } from "crypto";
3
+ import { Buffer } from "buffer";
4
+ import {
5
+ CONTEXT_STORE_INGEST_CONTRACT,
6
+ CONTEXT_STORE_MAX_QUERY_LIMIT,
7
+ CONTEXT_STORE_QUERY_CONTRACT,
8
+ contextStoreIngestInputSchema,
9
+ contextStoreIngestOutputSchema,
10
+ contextStoreQueryInputSchema,
11
+ contextStoreQueryOutputSchema,
12
+ requireServiceDependency,
13
+ serviceConfig,
14
+ UnsatisfiedServiceDependencyError
15
+ } from "gik-controlface/services";
16
+
17
+ // src/values.ts
18
+ function object(value, label) {
19
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
20
+ return value;
21
+ }
22
+ function text(value, label) {
23
+ if (typeof value !== "string" || !value.trim()) throw new Error(`${label} must be a nonempty string`);
24
+ return value;
25
+ }
26
+ function integer(value, label, minimum, maximum) {
27
+ if (typeof value !== "number" || !Number.isInteger(value) || value < minimum || value > maximum) {
28
+ throw new Error(`${label} must be an integer between ${minimum} and ${maximum}`);
29
+ }
30
+ return value;
31
+ }
32
+ function keys(value, allowed) {
33
+ const unexpected = Object.keys(value).filter((key) => !allowed.includes(key));
34
+ if (unexpected.length) throw new Error(`Unsupported input fields: ${unexpected.join(", ")}`);
35
+ }
36
+ function isJson(value) {
37
+ return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value) || Array.isArray(value) && value.every(isJson) || !!value && typeof value === "object" && Object.values(value).every(isJson);
38
+ }
39
+
40
+ // src/github-context-store.ts
41
+ var provider = { id: "github-context-store", version: "1" };
42
+ var recordMode = "100644";
43
+ var recordType = "blob";
44
+ var defaultMaxRecordsPerScope = 1e3;
45
+ var defaultMaxWriteAttempts = 3;
46
+ var GitHubContextRecordConflictError = class extends Error {
47
+ code = "github-context-record-conflict";
48
+ constructor(recordId) {
49
+ super(`GitHub context record '${recordId}' already exists with different content`);
50
+ this.name = "GitHubContextRecordConflictError";
51
+ }
52
+ };
53
+ var GitHubContextStoreRevisionConflictError = class extends Error {
54
+ constructor(ref, attempts) {
55
+ super(`GitHub context ref '${ref}' changed during ${attempts} write attempts`);
56
+ this.ref = ref;
57
+ this.attempts = attempts;
58
+ this.name = "GitHubContextStoreRevisionConflictError";
59
+ }
60
+ ref;
61
+ attempts;
62
+ code = "github-context-store-revision-conflict";
63
+ };
64
+ function isConnection(value) {
65
+ return !!value && typeof value === "object" && "request" in value && typeof value.request === "function";
66
+ }
67
+ function canonical(value) {
68
+ if (Array.isArray(value)) return value.map(canonical);
69
+ if (value && typeof value === "object") {
70
+ return Object.fromEntries(
71
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonical(entry)])
72
+ );
73
+ }
74
+ return value;
75
+ }
76
+ function serialize(value) {
77
+ if (!isJson(value)) throw new Error("GitHub context value must be JSON data");
78
+ return `${JSON.stringify(canonical(value))}
79
+ `;
80
+ }
81
+ function jsonValue(value, label) {
82
+ if (!isJson(value)) throw new Error(`${label} must be JSON data`);
83
+ return value;
84
+ }
85
+ function digest(value) {
86
+ return createHash("sha256").update(value).digest("hex");
87
+ }
88
+ function repositoryParts(repository) {
89
+ const parts = repository.split("/");
90
+ if (parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_.-]+$/.test(part))) {
91
+ throw new Error("GitHub context repository must be an owner/name pair");
92
+ }
93
+ return [parts[0], parts[1]];
94
+ }
95
+ function normalizedRef(value) {
96
+ if (!value.startsWith("refs/heads/")) {
97
+ throw new Error("GitHub context ref must start with 'refs/heads/'");
98
+ }
99
+ const branch = value.slice("refs/heads/".length);
100
+ if (!branch || branch.startsWith("/") || branch.endsWith("/") || branch.includes("//") || branch.split("/").some((part) => !part || part === "." || part === ".." || !/^[A-Za-z0-9._-]+$/.test(part))) {
101
+ throw new Error("GitHub context ref contains an unsafe branch name");
102
+ }
103
+ return `heads/${branch}`;
104
+ }
105
+ function normalizedPrefix(value) {
106
+ if (value.startsWith("/") || value.endsWith("/") || value.includes("\\") || value.split("/").some((part) => !part || part === "." || part === "..")) {
107
+ throw new Error("GitHub context prefix must be a safe repository-relative path");
108
+ }
109
+ return value;
110
+ }
111
+ function config(declaration) {
112
+ const value = serviceConfig(declaration);
113
+ const endpoint2 = text(value.endpoint, "endpoint");
114
+ const ref = text(value.ref, "ref");
115
+ if (endpoint2 !== "https://api.github.com") {
116
+ throw new Error("GitHub context endpoint must be https://api.github.com");
117
+ }
118
+ normalizedRef(ref);
119
+ return {
120
+ endpoint: endpoint2,
121
+ repository: text(value.repository, "repository"),
122
+ ref,
123
+ prefix: normalizedPrefix(text(value.prefix, "prefix")),
124
+ credentialRef: text(value.credentialRef, "credentialRef"),
125
+ maxRecordsPerScope: integer(
126
+ value.maxRecordsPerScope ?? defaultMaxRecordsPerScope,
127
+ "maxRecordsPerScope",
128
+ 1,
129
+ 5e3
130
+ ),
131
+ maxWriteAttempts: integer(
132
+ value.maxWriteAttempts ?? defaultMaxWriteAttempts,
133
+ "maxWriteAttempts",
134
+ 1,
135
+ 5
136
+ )
137
+ };
138
+ }
139
+ function credentialRequirement(declaration) {
140
+ const configured = config(declaration);
141
+ const writes = Object.values(declaration.operations).some(({ operation }) => operation === "ingest");
142
+ return {
143
+ id: "github-context-repository",
144
+ kind: "credential",
145
+ title: "GitHub context repository",
146
+ description: "Host-managed GitHub App connection for the declared context repository and ref",
147
+ ref: configured.credentialRef,
148
+ scheme: "github-app",
149
+ permissions: [writes ? "contents:write" : "contents:read"]
150
+ };
151
+ }
152
+ function validatedRecord(value) {
153
+ if (!isJson(value)) throw new Error("GitHub context record must be JSON data");
154
+ const record = object(value, "GitHub context record");
155
+ const id = text(record.id, "record id");
156
+ const kind = text(record.kind, "record kind");
157
+ const observedAt = text(record.observedAt, "record observedAt");
158
+ if (Number.isNaN(Date.parse(observedAt))) {
159
+ throw new Error("GitHub context record observedAt must be an ISO timestamp");
160
+ }
161
+ if (record.references !== void 0 && !Array.isArray(record.references)) {
162
+ throw new Error("GitHub context record references must be an array");
163
+ }
164
+ const result = { id, kind, observedAt };
165
+ for (const [key, entry] of Object.entries(record)) {
166
+ if (!isJson(entry)) throw new Error(`GitHub context record field '${key}' is not JSON data`);
167
+ result[key] = entry;
168
+ }
169
+ return result;
170
+ }
171
+ function jsonObject(value, label) {
172
+ const source = object(value, label);
173
+ const result = {};
174
+ for (const [key, entry] of Object.entries(source)) {
175
+ if (!isJson(entry)) throw new Error(`${label} field '${key}' is not JSON data`);
176
+ result[key] = entry;
177
+ }
178
+ return result;
179
+ }
180
+ function queryInput(value) {
181
+ const input = object(value, "GitHub context query");
182
+ keys(input, ["scope", "requestKey", "query", "limit"]);
183
+ return {
184
+ scope: text(input.scope, "scope"),
185
+ requestKey: text(input.requestKey, "requestKey"),
186
+ query: jsonObject(input.query, "query"),
187
+ limit: integer(input.limit, "limit", 1, CONTEXT_STORE_MAX_QUERY_LIMIT)
188
+ };
189
+ }
190
+ function ingestInput(value) {
191
+ const input = object(value, "GitHub context ingestion");
192
+ keys(input, ["scope", "records"]);
193
+ if (!Array.isArray(input.records)) throw new Error("GitHub context records must be an array");
194
+ const records = input.records.map(validatedRecord);
195
+ const identities = /* @__PURE__ */ new Map();
196
+ for (const record of records) {
197
+ const encoded = serialize(record);
198
+ const previous = identities.get(record.id);
199
+ if (previous !== void 0 && previous !== encoded) {
200
+ throw new GitHubContextRecordConflictError(record.id);
201
+ }
202
+ identities.set(record.id, encoded);
203
+ }
204
+ return { scope: text(input.scope, "scope"), records };
205
+ }
206
+ function apiPath(parts) {
207
+ return parts.map((part) => encodeURIComponent(part)).join("/");
208
+ }
209
+ function endpoint(configured, suffix) {
210
+ const [owner, repository] = repositoryParts(configured.repository);
211
+ return new URL(`/repos/${apiPath([owner, repository])}/${suffix}`, configured.endpoint);
212
+ }
213
+ function scopePaths(configured, scope) {
214
+ const root = `${configured.prefix}/scopes/${digest(scope)}`;
215
+ return {
216
+ metadata: `${root}/metadata.json`,
217
+ index: `${root}/recent.json`,
218
+ record: (id) => `${root}/records/${digest(id)}.json`
219
+ };
220
+ }
221
+ function jsonResponse(value, label) {
222
+ if (!isJson(value)) throw new Error(`${label} is not JSON data`);
223
+ return object(value, label);
224
+ }
225
+ function apiObject(value, label) {
226
+ const response = jsonResponse(value, label);
227
+ return { sha: text(response.sha, `${label} SHA`) };
228
+ }
229
+ function refResponse(value) {
230
+ const response = jsonResponse(value, "GitHub ref response");
231
+ const target = object(response.object, "GitHub ref object");
232
+ return { object: { sha: text(target.sha, "GitHub ref object SHA") } };
233
+ }
234
+ function commitResponse(value) {
235
+ const response = jsonResponse(value, "GitHub commit response");
236
+ const tree = object(response.tree, "GitHub commit tree");
237
+ return {
238
+ sha: text(response.sha, "GitHub commit SHA"),
239
+ tree: { sha: text(tree.sha, "GitHub commit tree SHA") }
240
+ };
241
+ }
242
+ function contentResponse(value) {
243
+ const response = jsonResponse(value, "GitHub content response");
244
+ if (response.type !== "file" || response.encoding !== "base64") {
245
+ throw new Error("GitHub content response is not a base64 file");
246
+ }
247
+ return {
248
+ type: "file",
249
+ encoding: "base64",
250
+ content: text(response.content, "GitHub content")
251
+ };
252
+ }
253
+ function scopeIndex(value, scope) {
254
+ const source = jsonResponse(value, "GitHub context scope index");
255
+ if (source.format !== "gik-github-context-recent/1" || source.scope !== scope || !Array.isArray(source.records)) {
256
+ throw new Error("GitHub context scope index is corrupt or belongs to another scope");
257
+ }
258
+ return {
259
+ format: "gik-github-context-recent/1",
260
+ scope,
261
+ records: source.records.map((entry) => {
262
+ const record = object(entry, "GitHub context scope index record");
263
+ return {
264
+ id: text(record.id, "indexed record id"),
265
+ observedAt: text(record.observedAt, "indexed record observedAt")
266
+ };
267
+ })
268
+ };
269
+ }
270
+ function createGitHubContextStoreServiceKind() {
271
+ return {
272
+ manifest: {
273
+ id: provider.id,
274
+ version: provider.version,
275
+ title: "GitHub-backed context store",
276
+ description: "Immutable bounded context records stored on a declared private GitHub ref",
277
+ configSchema: {
278
+ type: "object",
279
+ additionalProperties: false,
280
+ required: ["endpoint", "repository", "ref", "prefix", "credentialRef"],
281
+ properties: {
282
+ endpoint: { const: "https://api.github.com" },
283
+ repository: { type: "string", pattern: "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" },
284
+ ref: {
285
+ type: "string",
286
+ pattern: "^refs/heads/(?!\\.{1,2}(?:/|$))[A-Za-z0-9._-]+(?:/(?!\\.{1,2}(?:/|$))[A-Za-z0-9._-]+)*$"
287
+ },
288
+ prefix: { type: "string", minLength: 1 },
289
+ credentialRef: { type: "string", minLength: 1 },
290
+ maxRecordsPerScope: { type: "integer", minimum: 1, maximum: 5e3 },
291
+ maxWriteAttempts: { type: "integer", minimum: 1, maximum: 5 }
292
+ }
293
+ },
294
+ subjects: ["cell", "substrate-agent", "chat", "task"],
295
+ executionModes: ["immediate", "queued"],
296
+ supports: { discover: true, probe: true }
297
+ },
298
+ describeDependencies: (declaration) => [credentialRequirement(declaration)],
299
+ validate(declaration, context) {
300
+ try {
301
+ if (declaration.version !== "1") {
302
+ throw new Error("github-context-store supports version 1 only");
303
+ }
304
+ config(declaration);
305
+ if (!context.resolveCredential || !context.authorizeEndpoint) {
306
+ throw new Error(
307
+ "github-context-store requires host credential resolution and endpoint authorization"
308
+ );
309
+ }
310
+ if (!Object.keys(declaration.operations).length) {
311
+ throw new Error("github-context-store requires a declared operation");
312
+ }
313
+ for (const operation of Object.values(declaration.operations)) {
314
+ const contract = operation.operation === "query" ? CONTEXT_STORE_QUERY_CONTRACT : operation.operation === "ingest" ? CONTEXT_STORE_INGEST_CONTRACT : void 0;
315
+ if (!contract || operation.contract !== contract || operation.sense) {
316
+ throw new Error("Unsupported github-context-store operation or contract");
317
+ }
318
+ }
319
+ return { ok: true };
320
+ } catch (error) {
321
+ return { ok: false, errors: [error instanceof Error ? error.message : String(error)] };
322
+ }
323
+ },
324
+ create(declaration, context) {
325
+ const configured = config(declaration);
326
+ const ref = normalizedRef(configured.ref);
327
+ const requirement = credentialRequirement(declaration);
328
+ const operations = [...new Set(
329
+ Object.values(declaration.operations).map(({ operation }) => operation)
330
+ )];
331
+ async function call(path, method, body, signal, allowedStatuses = []) {
332
+ requireServiceDependency(context, requirement, context.identity?.serviceId ?? provider.id);
333
+ const url = endpoint(configured, path);
334
+ if (!context.authorizeEndpoint || !await context.authorizeEndpoint(provider.id, url)) {
335
+ throw new Error("Host denied the declared GitHub context-store endpoint");
336
+ }
337
+ const connection = await context.resolveCredential?.(configured.credentialRef);
338
+ if (!isConnection(connection)) {
339
+ throw new UnsatisfiedServiceDependencyError(
340
+ "Host must supply a GitHub context-store connection",
341
+ requirement,
342
+ {
343
+ dependencyStatus: {
344
+ state: "missing",
345
+ message: "Configure the host-managed GitHub App connection"
346
+ }
347
+ }
348
+ );
349
+ }
350
+ const abort = AbortSignal.any([
351
+ ...signal ? [signal] : [],
352
+ AbortSignal.timeout(3e4)
353
+ ]);
354
+ abort.throwIfAborted();
355
+ requireServiceDependency(context, requirement, context.identity?.serviceId ?? provider.id);
356
+ const response = await connection.request({
357
+ url: url.href,
358
+ method,
359
+ headers: {
360
+ accept: "application/vnd.github+json",
361
+ "content-type": "application/json",
362
+ "x-github-api-version": "2026-03-10"
363
+ },
364
+ ...body === void 0 ? {} : { body: JSON.stringify(body) },
365
+ signal: abort
366
+ });
367
+ if (response.status === 401) {
368
+ await context.clearCredential?.(configured.credentialRef);
369
+ throw new UnsatisfiedServiceDependencyError(
370
+ "GitHub context-store authorization expired",
371
+ requirement,
372
+ {
373
+ dependencyStatus: {
374
+ state: "authorization-required",
375
+ message: "Reconnect the GitHub App installation"
376
+ }
377
+ }
378
+ );
379
+ }
380
+ if (!response.ok && !allowedStatuses.includes(response.status)) {
381
+ throw new Error(
382
+ `GitHub context-store ${method} ${url.pathname} failed with HTTP ${response.status}`
383
+ );
384
+ }
385
+ if (response.status === 204 || allowedStatuses.includes(response.status)) {
386
+ return { response };
387
+ }
388
+ let value;
389
+ try {
390
+ value = await response.json();
391
+ } catch (error) {
392
+ throw new Error("GitHub context-store response is not valid JSON", { cause: error });
393
+ }
394
+ return { response, value };
395
+ }
396
+ async function head(signal) {
397
+ const reference = refResponse(
398
+ (await call(`git/ref/${apiPath(ref.split("/"))}`, "GET", void 0, signal)).value
399
+ );
400
+ const commit2 = commitResponse(
401
+ (await call(
402
+ `git/commits/${encodeURIComponent(reference.object.sha)}`,
403
+ "GET",
404
+ void 0,
405
+ signal
406
+ )).value
407
+ );
408
+ return commit2;
409
+ }
410
+ async function readPath(path, revision, signal) {
411
+ const url = `contents/${apiPath(path.split("/"))}?ref=${encodeURIComponent(revision)}`;
412
+ const result = await call(url, "GET", void 0, signal, [404]);
413
+ if (result.response.status === 404) return void 0;
414
+ const content = contentResponse(result.value);
415
+ try {
416
+ const value = JSON.parse(
417
+ Buffer.from(content.content.replace(/\s+/g, ""), "base64").toString("utf8")
418
+ );
419
+ if (!isJson(value)) throw new Error("Decoded value is not JSON data");
420
+ return value;
421
+ } catch (error) {
422
+ throw new Error(`GitHub context path '${path}' contains invalid JSON`, { cause: error });
423
+ }
424
+ }
425
+ async function createBlob(content, signal) {
426
+ const response = apiObject(
427
+ (await call("git/blobs", "POST", { content, encoding: "utf-8" }, signal)).value,
428
+ "GitHub blob response"
429
+ );
430
+ return response.sha;
431
+ }
432
+ async function commit(base, changes, message, signal) {
433
+ const treeEntries = await Promise.all(changes.map(async ({ path, content }) => ({
434
+ path,
435
+ mode: recordMode,
436
+ type: recordType,
437
+ sha: await createBlob(content, signal)
438
+ })));
439
+ const tree = apiObject(
440
+ (await call("git/trees", "POST", {
441
+ base_tree: base.tree.sha,
442
+ tree: treeEntries
443
+ }, signal)).value,
444
+ "GitHub tree response"
445
+ );
446
+ const created = apiObject(
447
+ (await call("git/commits", "POST", {
448
+ message,
449
+ tree: tree.sha,
450
+ parents: [base.sha]
451
+ }, signal)).value,
452
+ "GitHub commit response"
453
+ );
454
+ const revision = created.sha;
455
+ const update = await call(
456
+ `git/refs/${apiPath(ref.split("/"))}`,
457
+ "PATCH",
458
+ { sha: revision, force: false },
459
+ signal,
460
+ [409, 422]
461
+ );
462
+ return update.response.ok ? revision : void 0;
463
+ }
464
+ async function query(input, signal) {
465
+ const current = await head(signal);
466
+ const paths = scopePaths(configured, input.scope);
467
+ const storedIndex = await readPath(paths.index, current.sha, signal);
468
+ if (storedIndex === void 0) {
469
+ return {
470
+ output: { scope: input.scope, requestKey: input.requestKey, records: [] },
471
+ revision: current.sha
472
+ };
473
+ }
474
+ const index = scopeIndex(storedIndex, input.scope);
475
+ const records = await Promise.all(index.records.slice(0, input.limit).map(async (entry) => {
476
+ const id = text(entry?.id, "indexed record id");
477
+ const value = await readPath(paths.record(id), current.sha, signal);
478
+ if (value === void 0) {
479
+ throw new Error(`GitHub context scope index references missing record '${id}'`);
480
+ }
481
+ const record = validatedRecord(value);
482
+ if (record.id !== id) {
483
+ throw new Error(`GitHub context record path identity mismatch for '${id}'`);
484
+ }
485
+ return record;
486
+ }));
487
+ return {
488
+ output: {
489
+ scope: input.scope,
490
+ requestKey: input.requestKey,
491
+ records
492
+ },
493
+ revision: current.sha
494
+ };
495
+ }
496
+ async function ingest(input, signal) {
497
+ const paths = scopePaths(configured, input.scope);
498
+ for (let attempt = 1; attempt <= configured.maxWriteAttempts; attempt += 1) {
499
+ const current = await head(signal);
500
+ const metadataValue = await readPath(paths.metadata, current.sha, signal);
501
+ if (metadataValue !== void 0) {
502
+ const metadata = object(metadataValue, "GitHub context scope metadata");
503
+ if (metadata.format !== "gik-github-context-scope/1" || metadata.scope !== input.scope) {
504
+ throw new Error("GitHub context scope metadata is corrupt or hash-collided");
505
+ }
506
+ }
507
+ const storedIndex = await readPath(paths.index, current.sha, signal);
508
+ let index = {
509
+ format: "gik-github-context-recent/1",
510
+ scope: input.scope,
511
+ records: []
512
+ };
513
+ if (storedIndex !== void 0) {
514
+ index = scopeIndex(storedIndex, input.scope);
515
+ }
516
+ const changes = [];
517
+ const entries = new Map(index.records.map((entry) => [entry.id, entry]));
518
+ const unique = /* @__PURE__ */ new Map();
519
+ for (const record of input.records) unique.set(record.id, record);
520
+ for (const record of unique.values()) {
521
+ const path = paths.record(record.id);
522
+ const encoded = serialize(record);
523
+ const existing = await readPath(path, current.sha, signal);
524
+ if (existing !== void 0) {
525
+ const stored = validatedRecord(existing);
526
+ if (stored.id !== record.id || serialize(stored) !== encoded) {
527
+ throw new GitHubContextRecordConflictError(record.id);
528
+ }
529
+ } else {
530
+ changes.push({ path, content: encoded });
531
+ }
532
+ entries.set(record.id, { id: record.id, observedAt: record.observedAt });
533
+ }
534
+ const nextRecords = [...entries.values()].sort((left, right) => right.observedAt.localeCompare(left.observedAt) || left.id.localeCompare(right.id)).slice(0, configured.maxRecordsPerScope);
535
+ const nextIndex = { ...index, records: nextRecords };
536
+ if (metadataValue === void 0) {
537
+ changes.push({
538
+ path: paths.metadata,
539
+ content: serialize({
540
+ format: "gik-github-context-scope/1",
541
+ scope: input.scope
542
+ })
543
+ });
544
+ }
545
+ if (storedIndex === void 0 || serialize(storedIndex) !== serialize(nextIndex)) {
546
+ changes.push({
547
+ path: paths.index,
548
+ content: serialize(nextIndex)
549
+ });
550
+ }
551
+ if (!changes.length) {
552
+ return {
553
+ output: {
554
+ scope: input.scope,
555
+ recordIds: input.records.map(({ id }) => id),
556
+ status: "stored"
557
+ },
558
+ revision: current.sha
559
+ };
560
+ }
561
+ const revision = await commit(
562
+ current,
563
+ changes,
564
+ `context: ingest ${input.records.length} record(s) for ${digest(input.scope).slice(0, 12)}`,
565
+ signal
566
+ );
567
+ if (revision) {
568
+ return {
569
+ output: {
570
+ scope: input.scope,
571
+ recordIds: input.records.map(({ id }) => id),
572
+ status: "stored"
573
+ },
574
+ revision
575
+ };
576
+ }
577
+ }
578
+ throw new GitHubContextStoreRevisionConflictError(
579
+ configured.ref,
580
+ configured.maxWriteAttempts
581
+ );
582
+ }
583
+ return {
584
+ provider,
585
+ discover: async () => ({
586
+ provider,
587
+ revision: "1",
588
+ discoveredAt: (/* @__PURE__ */ new Date()).toISOString(),
589
+ capabilities: operations.map((operation) => ({
590
+ id: operation === "query" ? CONTEXT_STORE_QUERY_CONTRACT : CONTEXT_STORE_INGEST_CONTRACT,
591
+ operation,
592
+ name: operation === "query" ? "Query GitHub context" : "Ingest GitHub context",
593
+ version: "1",
594
+ inputSchema: operation === "query" ? contextStoreQueryInputSchema : contextStoreIngestInputSchema,
595
+ outputSchema: operation === "query" ? contextStoreQueryOutputSchema : contextStoreIngestOutputSchema,
596
+ assurance: "declared-and-locally-validated"
597
+ }))
598
+ }),
599
+ async probe(adapterContext) {
600
+ const current = await head(adapterContext.signal);
601
+ return {
602
+ ok: true,
603
+ detail: {
604
+ repository: configured.repository,
605
+ ref: configured.ref,
606
+ revision: current.sha
607
+ }
608
+ };
609
+ },
610
+ async execute(request, adapterContext) {
611
+ if (!operations.includes(request.operation)) {
612
+ throw new Error("GitHub context-store operation is not declared");
613
+ }
614
+ if (request.operation === "query") {
615
+ const result = await query(queryInput(request.input), adapterContext.signal);
616
+ return {
617
+ output: jsonValue(result.output, "GitHub context query output"),
618
+ detail: {
619
+ repository: configured.repository,
620
+ ref: configured.ref,
621
+ revision: result.revision
622
+ }
623
+ };
624
+ }
625
+ if (request.operation === "ingest") {
626
+ const result = await ingest(ingestInput(request.input), adapterContext.signal);
627
+ return {
628
+ output: jsonValue(result.output, "GitHub context ingestion output"),
629
+ detail: {
630
+ repository: configured.repository,
631
+ ref: configured.ref,
632
+ revision: result.revision
633
+ }
634
+ };
635
+ }
636
+ throw new Error("Unsupported GitHub context-store operation");
637
+ }
638
+ };
639
+ }
640
+ };
641
+ }
642
+ export {
643
+ GitHubContextRecordConflictError,
644
+ GitHubContextStoreRevisionConflictError,
645
+ createGitHubContextStoreServiceKind
646
+ };
647
+ //# sourceMappingURL=github-context-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/github-context-store.ts","../src/values.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { Buffer } from \"node:buffer\";\n\nimport {\n CONTEXT_STORE_INGEST_CONTRACT,\n CONTEXT_STORE_MAX_QUERY_LIMIT,\n CONTEXT_STORE_QUERY_CONTRACT,\n contextStoreIngestInputSchema,\n contextStoreIngestOutputSchema,\n contextStoreQueryInputSchema,\n contextStoreQueryOutputSchema,\n requireServiceDependency,\n serviceConfig,\n UnsatisfiedServiceDependencyError,\n type ContextRecord,\n type ContextStoreIngestInput,\n type ContextStoreIngestOutput,\n type ContextStoreQueryInput,\n type ContextStoreQueryOutput,\n type ServiceDependencyRequirement,\n type ServiceKindContext,\n type ServiceKindFactory,\n type ServiceRequest,\n} from \"gik-controlface/services\";\nimport type { Json, NativeServiceDeclaration } from \"gik-kernel\";\nimport { integer, isJson, keys, object, text } from \"./values\";\n\nconst provider = { id: \"github-context-store\", version: \"1\" };\nconst recordMode = \"100644\";\nconst recordType = \"blob\";\nconst defaultMaxRecordsPerScope = 1000;\nconst defaultMaxWriteAttempts = 3;\n\nexport interface GitHubContextStoreHttpRequest {\n url: string;\n method: \"GET\" | \"POST\" | \"PATCH\";\n headers: Readonly<Record<string, string>>;\n body?: string;\n signal: AbortSignal;\n}\n\n/** The host owns authentication and adds it inside this connection. */\nexport interface GitHubContextStoreConnection {\n request(request: Readonly<GitHubContextStoreHttpRequest>): Promise<Response>;\n}\n\nexport class GitHubContextRecordConflictError extends Error {\n readonly code = \"github-context-record-conflict\";\n\n constructor(recordId: string) {\n super(`GitHub context record '${recordId}' already exists with different content`);\n this.name = \"GitHubContextRecordConflictError\";\n }\n}\n\nexport class GitHubContextStoreRevisionConflictError extends Error {\n readonly code = \"github-context-store-revision-conflict\";\n\n constructor(readonly ref: string, readonly attempts: number) {\n super(`GitHub context ref '${ref}' changed during ${attempts} write attempts`);\n this.name = \"GitHubContextStoreRevisionConflictError\";\n }\n}\n\ninterface GitHubContextStoreConfig {\n endpoint: string;\n repository: string;\n ref: string;\n prefix: string;\n credentialRef: string;\n maxRecordsPerScope: number;\n maxWriteAttempts: number;\n}\n\ninterface ScopeIndex {\n format: \"gik-github-context-recent/1\";\n scope: string;\n records: Array<{ id: string; observedAt: string }>;\n}\n\ninterface GitHubApiObject {\n sha: string;\n}\n\ninterface GitHubRefResponse {\n object: GitHubApiObject;\n}\n\ninterface GitHubCommitResponse extends GitHubApiObject {\n tree: GitHubApiObject;\n}\n\ninterface GitHubContentResponse {\n type: \"file\";\n encoding: \"base64\";\n content: string;\n}\n\nfunction isConnection(value: unknown): value is GitHubContextStoreConnection {\n return !!value && typeof value === \"object\"\n && \"request\" in value && typeof value.request === \"function\";\n}\n\nfunction canonical(value: Json): Json {\n if (Array.isArray(value)) return value.map(canonical);\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => [key, canonical(entry)]),\n );\n }\n return value;\n}\n\nfunction serialize(value: unknown): string {\n if (!isJson(value)) throw new Error(\"GitHub context value must be JSON data\");\n return `${JSON.stringify(canonical(value))}\\n`;\n}\n\nfunction jsonValue(value: unknown, label: string): Json {\n if (!isJson(value)) throw new Error(`${label} must be JSON data`);\n return value;\n}\n\nfunction digest(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction repositoryParts(repository: string): [string, string] {\n const parts = repository.split(\"/\");\n if (parts.length !== 2 || parts.some((part) => !/^[A-Za-z0-9_.-]+$/.test(part))) {\n throw new Error(\"GitHub context repository must be an owner/name pair\");\n }\n return [parts[0], parts[1]];\n}\n\nfunction normalizedRef(value: string): string {\n if (!value.startsWith(\"refs/heads/\")) {\n throw new Error(\"GitHub context ref must start with 'refs/heads/'\");\n }\n const branch = value.slice(\"refs/heads/\".length);\n if (!branch || branch.startsWith(\"/\") || branch.endsWith(\"/\")\n || branch.includes(\"//\") || branch.split(\"/\").some((part) =>\n !part || part === \".\" || part === \"..\" || !/^[A-Za-z0-9._-]+$/.test(part))) {\n throw new Error(\"GitHub context ref contains an unsafe branch name\");\n }\n return `heads/${branch}`;\n}\n\nfunction normalizedPrefix(value: string): string {\n if (value.startsWith(\"/\") || value.endsWith(\"/\") || value.includes(\"\\\\\")\n || value.split(\"/\").some((part) => !part || part === \".\" || part === \"..\")) {\n throw new Error(\"GitHub context prefix must be a safe repository-relative path\");\n }\n return value;\n}\n\nfunction config(declaration: NativeServiceDeclaration): GitHubContextStoreConfig {\n const value = serviceConfig(declaration);\n const endpoint = text(value.endpoint, \"endpoint\");\n const ref = text(value.ref, \"ref\");\n if (endpoint !== \"https://api.github.com\") {\n throw new Error(\"GitHub context endpoint must be https://api.github.com\");\n }\n normalizedRef(ref);\n return {\n endpoint,\n repository: text(value.repository, \"repository\"),\n ref,\n prefix: normalizedPrefix(text(value.prefix, \"prefix\")),\n credentialRef: text(value.credentialRef, \"credentialRef\"),\n maxRecordsPerScope: integer(\n value.maxRecordsPerScope ?? defaultMaxRecordsPerScope,\n \"maxRecordsPerScope\",\n 1,\n 5000,\n ),\n maxWriteAttempts: integer(\n value.maxWriteAttempts ?? defaultMaxWriteAttempts,\n \"maxWriteAttempts\",\n 1,\n 5,\n ),\n };\n}\n\nfunction credentialRequirement(declaration: NativeServiceDeclaration): ServiceDependencyRequirement {\n const configured = config(declaration);\n const writes = Object.values(declaration.operations)\n .some(({ operation }) => operation === \"ingest\");\n return {\n id: \"github-context-repository\",\n kind: \"credential\",\n title: \"GitHub context repository\",\n description: \"Host-managed GitHub App connection for the declared context repository and ref\",\n ref: configured.credentialRef,\n scheme: \"github-app\",\n permissions: [writes ? \"contents:write\" : \"contents:read\"],\n };\n}\n\nfunction validatedRecord(value: unknown): ContextRecord {\n if (!isJson(value)) throw new Error(\"GitHub context record must be JSON data\");\n const record = object(value, \"GitHub context record\");\n const id = text(record.id, \"record id\");\n const kind = text(record.kind, \"record kind\");\n const observedAt = text(record.observedAt, \"record observedAt\");\n if (Number.isNaN(Date.parse(observedAt))) {\n throw new Error(\"GitHub context record observedAt must be an ISO timestamp\");\n }\n if (record.references !== undefined && !Array.isArray(record.references)) {\n throw new Error(\"GitHub context record references must be an array\");\n }\n const result: ContextRecord = { id, kind, observedAt };\n for (const [key, entry] of Object.entries(record)) {\n if (!isJson(entry)) throw new Error(`GitHub context record field '${key}' is not JSON data`);\n result[key] = entry;\n }\n return result;\n}\n\nfunction jsonObject(value: unknown, label: string): Record<string, Json> {\n const source = object(value, label);\n const result: Record<string, Json> = {};\n for (const [key, entry] of Object.entries(source)) {\n if (!isJson(entry)) throw new Error(`${label} field '${key}' is not JSON data`);\n result[key] = entry;\n }\n return result;\n}\n\nfunction queryInput(value: unknown): ContextStoreQueryInput {\n const input = object(value, \"GitHub context query\");\n keys(input, [\"scope\", \"requestKey\", \"query\", \"limit\"]);\n return {\n scope: text(input.scope, \"scope\"),\n requestKey: text(input.requestKey, \"requestKey\"),\n query: jsonObject(input.query, \"query\"),\n limit: integer(input.limit, \"limit\", 1, CONTEXT_STORE_MAX_QUERY_LIMIT),\n };\n}\n\nfunction ingestInput(value: unknown): ContextStoreIngestInput {\n const input = object(value, \"GitHub context ingestion\");\n keys(input, [\"scope\", \"records\"]);\n if (!Array.isArray(input.records)) throw new Error(\"GitHub context records must be an array\");\n const records = input.records.map(validatedRecord);\n const identities = new Map<string, string>();\n for (const record of records) {\n const encoded = serialize(record);\n const previous = identities.get(record.id);\n if (previous !== undefined && previous !== encoded) {\n throw new GitHubContextRecordConflictError(record.id);\n }\n identities.set(record.id, encoded);\n }\n return { scope: text(input.scope, \"scope\"), records };\n}\n\nfunction apiPath(parts: string[]): string {\n return parts.map((part) => encodeURIComponent(part)).join(\"/\");\n}\n\nfunction endpoint(configured: GitHubContextStoreConfig, suffix: string): URL {\n const [owner, repository] = repositoryParts(configured.repository);\n return new URL(`/repos/${apiPath([owner, repository])}/${suffix}`, configured.endpoint);\n}\n\nfunction scopePaths(configured: GitHubContextStoreConfig, scope: string) {\n const root = `${configured.prefix}/scopes/${digest(scope)}`;\n return {\n metadata: `${root}/metadata.json`,\n index: `${root}/recent.json`,\n record: (id: string) => `${root}/records/${digest(id)}.json`,\n };\n}\n\nfunction jsonResponse(value: unknown, label: string): Record<string, unknown> {\n if (!isJson(value)) throw new Error(`${label} is not JSON data`);\n return object(value, label);\n}\n\nfunction apiObject(value: unknown, label: string): GitHubApiObject {\n const response = jsonResponse(value, label);\n return { sha: text(response.sha, `${label} SHA`) };\n}\n\nfunction refResponse(value: unknown): GitHubRefResponse {\n const response = jsonResponse(value, \"GitHub ref response\");\n const target = object(response.object, \"GitHub ref object\");\n return { object: { sha: text(target.sha, \"GitHub ref object SHA\") } };\n}\n\nfunction commitResponse(value: unknown): GitHubCommitResponse {\n const response = jsonResponse(value, \"GitHub commit response\");\n const tree = object(response.tree, \"GitHub commit tree\");\n return {\n sha: text(response.sha, \"GitHub commit SHA\"),\n tree: { sha: text(tree.sha, \"GitHub commit tree SHA\") },\n };\n}\n\nfunction contentResponse(value: unknown): GitHubContentResponse {\n const response = jsonResponse(value, \"GitHub content response\");\n if (response.type !== \"file\" || response.encoding !== \"base64\") {\n throw new Error(\"GitHub content response is not a base64 file\");\n }\n return {\n type: \"file\",\n encoding: \"base64\",\n content: text(response.content, \"GitHub content\"),\n };\n}\n\nfunction scopeIndex(value: unknown, scope: string): ScopeIndex {\n const source = jsonResponse(value, \"GitHub context scope index\");\n if (source.format !== \"gik-github-context-recent/1\"\n || source.scope !== scope || !Array.isArray(source.records)) {\n throw new Error(\"GitHub context scope index is corrupt or belongs to another scope\");\n }\n return {\n format: \"gik-github-context-recent/1\",\n scope,\n records: source.records.map((entry) => {\n const record = object(entry, \"GitHub context scope index record\");\n return {\n id: text(record.id, \"indexed record id\"),\n observedAt: text(record.observedAt, \"indexed record observedAt\"),\n };\n }),\n };\n}\n\nexport function createGitHubContextStoreServiceKind(): ServiceKindFactory {\n return {\n manifest: {\n id: provider.id,\n version: provider.version,\n title: \"GitHub-backed context store\",\n description: \"Immutable bounded context records stored on a declared private GitHub ref\",\n configSchema: {\n type: \"object\",\n additionalProperties: false,\n required: [\"endpoint\", \"repository\", \"ref\", \"prefix\", \"credentialRef\"],\n properties: {\n endpoint: { const: \"https://api.github.com\" },\n repository: { type: \"string\", pattern: \"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$\" },\n ref: {\n type: \"string\",\n pattern:\n \"^refs/heads/(?!\\\\.{1,2}(?:/|$))[A-Za-z0-9._-]+(?:/(?!\\\\.{1,2}(?:/|$))[A-Za-z0-9._-]+)*$\",\n },\n prefix: { type: \"string\", minLength: 1 },\n credentialRef: { type: \"string\", minLength: 1 },\n maxRecordsPerScope: { type: \"integer\", minimum: 1, maximum: 5000 },\n maxWriteAttempts: { type: \"integer\", minimum: 1, maximum: 5 },\n },\n },\n subjects: [\"cell\", \"substrate-agent\", \"chat\", \"task\"],\n executionModes: [\"immediate\", \"queued\"],\n supports: { discover: true, probe: true },\n },\n describeDependencies: (declaration) => [credentialRequirement(declaration)],\n validate(declaration, context) {\n try {\n if (declaration.version !== \"1\") {\n throw new Error(\"github-context-store supports version 1 only\");\n }\n config(declaration);\n if (!context.resolveCredential || !context.authorizeEndpoint) {\n throw new Error(\n \"github-context-store requires host credential resolution and endpoint authorization\",\n );\n }\n if (!Object.keys(declaration.operations).length) {\n throw new Error(\"github-context-store requires a declared operation\");\n }\n for (const operation of Object.values(declaration.operations)) {\n const contract = operation.operation === \"query\"\n ? CONTEXT_STORE_QUERY_CONTRACT\n : operation.operation === \"ingest\"\n ? CONTEXT_STORE_INGEST_CONTRACT\n : undefined;\n if (!contract || operation.contract !== contract || operation.sense) {\n throw new Error(\"Unsupported github-context-store operation or contract\");\n }\n }\n return { ok: true };\n } catch (error) {\n return { ok: false, errors: [error instanceof Error ? error.message : String(error)] };\n }\n },\n create(declaration, context) {\n const configured = config(declaration);\n const ref = normalizedRef(configured.ref);\n const requirement = credentialRequirement(declaration);\n const operations = [...new Set(\n Object.values(declaration.operations).map(({ operation }) => operation),\n )];\n\n async function call(\n path: string,\n method: GitHubContextStoreHttpRequest[\"method\"],\n body?: Json,\n signal?: AbortSignal,\n allowedStatuses: readonly number[] = [],\n ): Promise<{ response: Response; value?: unknown }> {\n requireServiceDependency(context, requirement, context.identity?.serviceId ?? provider.id);\n const url = endpoint(configured, path);\n if (!context.authorizeEndpoint\n || !await context.authorizeEndpoint(provider.id, url)) {\n throw new Error(\"Host denied the declared GitHub context-store endpoint\");\n }\n const connection = await context.resolveCredential?.(configured.credentialRef);\n if (!isConnection(connection)) {\n throw new UnsatisfiedServiceDependencyError(\n \"Host must supply a GitHub context-store connection\",\n requirement,\n {\n dependencyStatus: {\n state: \"missing\",\n message: \"Configure the host-managed GitHub App connection\",\n },\n },\n );\n }\n const abort = AbortSignal.any([\n ...(signal ? [signal] : []),\n AbortSignal.timeout(30000),\n ]);\n abort.throwIfAborted();\n requireServiceDependency(context, requirement, context.identity?.serviceId ?? provider.id);\n const response = await connection.request({\n url: url.href,\n method,\n headers: {\n accept: \"application/vnd.github+json\",\n \"content-type\": \"application/json\",\n \"x-github-api-version\": \"2026-03-10\",\n },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n signal: abort,\n });\n if (response.status === 401) {\n await context.clearCredential?.(configured.credentialRef);\n throw new UnsatisfiedServiceDependencyError(\n \"GitHub context-store authorization expired\",\n requirement,\n {\n dependencyStatus: {\n state: \"authorization-required\",\n message: \"Reconnect the GitHub App installation\",\n },\n },\n );\n }\n if (!response.ok && !allowedStatuses.includes(response.status)) {\n throw new Error(\n `GitHub context-store ${method} ${url.pathname} failed with HTTP ${response.status}`,\n );\n }\n if (response.status === 204 || allowedStatuses.includes(response.status)) {\n return { response };\n }\n let value: unknown;\n try {\n value = await response.json();\n } catch (error) {\n throw new Error(\"GitHub context-store response is not valid JSON\", { cause: error });\n }\n return { response, value };\n }\n\n async function head(signal?: AbortSignal): Promise<GitHubCommitResponse> {\n const reference = refResponse(\n (await call(`git/ref/${apiPath(ref.split(\"/\"))}`, \"GET\", undefined, signal)).value,\n );\n const commit = commitResponse(\n (await call(\n `git/commits/${encodeURIComponent(reference.object.sha)}`,\n \"GET\",\n undefined,\n signal,\n )).value,\n );\n return commit;\n }\n\n async function readPath(\n path: string,\n revision: string,\n signal?: AbortSignal,\n ): Promise<Json | undefined> {\n const url = `contents/${apiPath(path.split(\"/\"))}?ref=${encodeURIComponent(revision)}`;\n const result = await call(url, \"GET\", undefined, signal, [404]);\n if (result.response.status === 404) return undefined;\n const content = contentResponse(result.value);\n try {\n const value: unknown = JSON.parse(\n Buffer.from(content.content.replace(/\\s+/g, \"\"), \"base64\").toString(\"utf8\"),\n );\n if (!isJson(value)) throw new Error(\"Decoded value is not JSON data\");\n return value;\n } catch (error) {\n throw new Error(`GitHub context path '${path}' contains invalid JSON`, { cause: error });\n }\n }\n\n async function createBlob(content: string, signal?: AbortSignal): Promise<string> {\n const response = apiObject(\n (await call(\"git/blobs\", \"POST\", { content, encoding: \"utf-8\" }, signal)).value,\n \"GitHub blob response\",\n );\n return response.sha;\n }\n\n async function commit(\n base: GitHubCommitResponse,\n changes: Array<{ path: string; content: string }>,\n message: string,\n signal?: AbortSignal,\n ): Promise<string | undefined> {\n const treeEntries = await Promise.all(changes.map(async ({ path, content }) => ({\n path,\n mode: recordMode,\n type: recordType,\n sha: await createBlob(content, signal),\n })));\n const tree = apiObject(\n (await call(\"git/trees\", \"POST\", {\n base_tree: base.tree.sha,\n tree: treeEntries,\n }, signal)).value,\n \"GitHub tree response\",\n );\n const created = apiObject(\n (await call(\"git/commits\", \"POST\", {\n message,\n tree: tree.sha,\n parents: [base.sha],\n }, signal)).value,\n \"GitHub commit response\",\n );\n const revision = created.sha;\n const update = await call(\n `git/refs/${apiPath(ref.split(\"/\"))}`,\n \"PATCH\",\n { sha: revision, force: false },\n signal,\n [409, 422],\n );\n return update.response.ok ? revision : undefined;\n }\n\n async function query(\n input: ContextStoreQueryInput,\n signal?: AbortSignal,\n ): Promise<{ output: ContextStoreQueryOutput; revision: string }> {\n const current = await head(signal);\n const paths = scopePaths(configured, input.scope);\n const storedIndex = await readPath(paths.index, current.sha, signal);\n if (storedIndex === undefined) {\n return {\n output: { scope: input.scope, requestKey: input.requestKey, records: [] },\n revision: current.sha,\n };\n }\n const index = scopeIndex(storedIndex, input.scope);\n const records = await Promise.all(index.records.slice(0, input.limit).map(async (entry) => {\n const id = text(entry?.id, \"indexed record id\");\n const value = await readPath(paths.record(id), current.sha, signal);\n if (value === undefined) {\n throw new Error(`GitHub context scope index references missing record '${id}'`);\n }\n const record = validatedRecord(value);\n if (record.id !== id) {\n throw new Error(`GitHub context record path identity mismatch for '${id}'`);\n }\n return record;\n }));\n return {\n output: {\n scope: input.scope,\n requestKey: input.requestKey,\n records,\n },\n revision: current.sha,\n };\n }\n\n async function ingest(\n input: ContextStoreIngestInput,\n signal?: AbortSignal,\n ): Promise<{ output: ContextStoreIngestOutput; revision: string }> {\n const paths = scopePaths(configured, input.scope);\n for (let attempt = 1; attempt <= configured.maxWriteAttempts; attempt += 1) {\n const current = await head(signal);\n const metadataValue = await readPath(paths.metadata, current.sha, signal);\n if (metadataValue !== undefined) {\n const metadata = object(metadataValue, \"GitHub context scope metadata\");\n if (metadata.format !== \"gik-github-context-scope/1\"\n || metadata.scope !== input.scope) {\n throw new Error(\"GitHub context scope metadata is corrupt or hash-collided\");\n }\n }\n const storedIndex = await readPath(paths.index, current.sha, signal);\n let index: ScopeIndex = {\n format: \"gik-github-context-recent/1\",\n scope: input.scope,\n records: [],\n };\n if (storedIndex !== undefined) {\n index = scopeIndex(storedIndex, input.scope);\n }\n\n const changes: Array<{ path: string; content: string }> = [];\n const entries = new Map(index.records.map((entry) => [entry.id, entry]));\n const unique = new Map<string, ContextRecord>();\n for (const record of input.records) unique.set(record.id, record);\n for (const record of unique.values()) {\n const path = paths.record(record.id);\n const encoded = serialize(record);\n const existing = await readPath(path, current.sha, signal);\n if (existing !== undefined) {\n const stored = validatedRecord(existing);\n if (stored.id !== record.id || serialize(stored) !== encoded) {\n throw new GitHubContextRecordConflictError(record.id);\n }\n } else {\n changes.push({ path, content: encoded });\n }\n entries.set(record.id, { id: record.id, observedAt: record.observedAt });\n }\n\n const nextRecords = [...entries.values()]\n .sort((left, right) =>\n right.observedAt.localeCompare(left.observedAt)\n || left.id.localeCompare(right.id))\n .slice(0, configured.maxRecordsPerScope);\n const nextIndex: ScopeIndex = { ...index, records: nextRecords };\n if (metadataValue === undefined) {\n changes.push({\n path: paths.metadata,\n content: serialize({\n format: \"gik-github-context-scope/1\",\n scope: input.scope,\n }),\n });\n }\n if (storedIndex === undefined\n || serialize(storedIndex) !== serialize(nextIndex)) {\n changes.push({\n path: paths.index,\n content: serialize(nextIndex),\n });\n }\n\n if (!changes.length) {\n return {\n output: {\n scope: input.scope,\n recordIds: input.records.map(({ id }) => id),\n status: \"stored\",\n },\n revision: current.sha,\n };\n }\n const revision = await commit(\n current,\n changes,\n `context: ingest ${input.records.length} record(s) for ${digest(input.scope).slice(0, 12)}`,\n signal,\n );\n if (revision) {\n return {\n output: {\n scope: input.scope,\n recordIds: input.records.map(({ id }) => id),\n status: \"stored\",\n },\n revision,\n };\n }\n }\n throw new GitHubContextStoreRevisionConflictError(\n configured.ref,\n configured.maxWriteAttempts,\n );\n }\n\n return {\n provider,\n discover: async () => ({\n provider,\n revision: \"1\",\n discoveredAt: new Date().toISOString(),\n capabilities: operations.map((operation) => ({\n id: operation === \"query\"\n ? CONTEXT_STORE_QUERY_CONTRACT\n : CONTEXT_STORE_INGEST_CONTRACT,\n operation,\n name: operation === \"query\"\n ? \"Query GitHub context\"\n : \"Ingest GitHub context\",\n version: \"1\",\n inputSchema: operation === \"query\"\n ? contextStoreQueryInputSchema\n : contextStoreIngestInputSchema,\n outputSchema: operation === \"query\"\n ? contextStoreQueryOutputSchema\n : contextStoreIngestOutputSchema,\n assurance: \"declared-and-locally-validated\",\n })),\n }),\n async probe(adapterContext) {\n const current = await head(adapterContext.signal);\n return {\n ok: true,\n detail: {\n repository: configured.repository,\n ref: configured.ref,\n revision: current.sha,\n },\n };\n },\n async execute(request: ServiceRequest, adapterContext) {\n if (!operations.includes(request.operation)) {\n throw new Error(\"GitHub context-store operation is not declared\");\n }\n if (request.operation === \"query\") {\n const result = await query(queryInput(request.input), adapterContext.signal);\n return {\n output: jsonValue(result.output, \"GitHub context query output\"),\n detail: {\n repository: configured.repository,\n ref: configured.ref,\n revision: result.revision,\n },\n };\n }\n if (request.operation === \"ingest\") {\n const result = await ingest(ingestInput(request.input), adapterContext.signal);\n return {\n output: jsonValue(result.output, \"GitHub context ingestion output\"),\n detail: {\n repository: configured.repository,\n ref: configured.ref,\n revision: result.revision,\n },\n };\n }\n throw new Error(\"Unsupported GitHub context-store operation\");\n },\n };\n },\n };\n}\n","import type { Json } from \"gik-kernel\";\n\nexport function object(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error(`${label} must be an object`);\n return value as Record<string, unknown>;\n}\n\nexport function text(value: unknown, label: string): string {\n if (typeof value !== \"string\" || !value.trim()) throw new Error(`${label} must be a nonempty string`);\n return value;\n}\n\nexport function integer(value: unknown, label: string, minimum: number, maximum: number): number {\n if (typeof value !== \"number\" || !Number.isInteger(value) || value < minimum || value > maximum) {\n throw new Error(`${label} must be an integer between ${minimum} and ${maximum}`);\n }\n return value;\n}\n\nexport function keys(value: Record<string, unknown>, allowed: string[]): void {\n const unexpected = Object.keys(value).filter((key) => !allowed.includes(key));\n if (unexpected.length) throw new Error(`Unsupported input fields: ${unexpected.join(\", \")}`);\n}\n\nexport function isJson(value: unknown): value is Json {\n return value === null || typeof value === \"string\" || typeof value === \"boolean\"\n || typeof value === \"number\" && Number.isFinite(value)\n || Array.isArray(value) && value.every(isJson)\n || !!value && typeof value === \"object\" && Object.values(value).every(isJson);\n}\n"],"mappings":"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","names":["endpoint","commit"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gik-service-providers",
3
- "version": "0.1.0",
4
- "description": "Individually imported host-managed scheduler and Gmail providers for GIK.",
3
+ "version": "0.2.0",
4
+ "description": "Individually imported host-managed service providers for GIK.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "nsreehari",
@@ -11,10 +11,24 @@
11
11
  "directory": "packages/service-providers"
12
12
  },
13
13
  "sideEffects": false,
14
- "files": ["dist", "README.md", "examples"],
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "examples"
18
+ ],
15
19
  "exports": {
16
- "./scheduler": { "types": "./dist/scheduler.d.ts", "import": "./dist/scheduler.js" },
17
- "./gmail": { "types": "./dist/gmail.d.ts", "import": "./dist/gmail.js" }
20
+ "./scheduler": {
21
+ "types": "./dist/scheduler.d.ts",
22
+ "import": "./dist/scheduler.js"
23
+ },
24
+ "./gmail": {
25
+ "types": "./dist/gmail.d.ts",
26
+ "import": "./dist/gmail.js"
27
+ },
28
+ "./github-context-store": {
29
+ "types": "./dist/github-context-store.d.ts",
30
+ "import": "./dist/github-context-store.js"
31
+ }
18
32
  },
19
33
  "dependencies": {
20
34
  "croner": "^9.1.0",
@@ -26,5 +40,8 @@
26
40
  "prepack": "npm run build",
27
41
  "typecheck": "tsc -p tsconfig.json --noEmit"
28
42
  },
29
- "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" }
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "registry": "https://registry.npmjs.org/"
46
+ }
30
47
  }