modjules 0.1.1 → 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 +10 -6
- package/dist/activities/client.d.ts +44 -1
- package/dist/activities/types.d.ts +7 -0
- package/dist/activity/summary.d.ts +7 -0
- package/dist/api.d.ts +31 -1
- package/dist/artifacts.d.ts +22 -1
- package/dist/browser.d.ts +9 -1
- package/dist/browser.mjs +304 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/caching.d.ts +16 -0
- package/dist/client.d.ts +53 -1
- package/dist/errors.d.ts +7 -0
- package/dist/github/adapter.d.ts +2 -0
- package/dist/github/api.d.ts +6 -0
- package/dist/github/caching.d.ts +2 -0
- package/dist/github/errors.d.ts +17 -0
- package/dist/github/index.d.ts +3 -0
- package/dist/github/pr-client.d.ts +12 -0
- package/dist/github/types.d.ts +72 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.mjs +1438 -0
- package/dist/index.mjs.map +1 -0
- package/dist/memory-DE2Wujcu.js +2573 -0
- package/dist/memory-DE2Wujcu.js.map +1 -0
- package/dist/platform/browser.d.ts +13 -1
- package/dist/platform/node.d.ts +15 -1
- package/dist/platform/types.d.ts +56 -1
- package/dist/platform/web.d.ts +29 -0
- package/dist/query/computed.d.ts +65 -0
- package/dist/query/projection.d.ts +65 -0
- package/dist/query/schema.d.ts +109 -0
- package/dist/query/select.d.ts +6 -0
- package/dist/query/validate.d.ts +59 -0
- package/dist/session.d.ts +30 -6
- package/dist/sessions.d.ts +65 -0
- package/dist/snapshot.d.ts +23 -0
- package/dist/storage/cache-info.d.ts +28 -0
- package/dist/storage/memory.d.ts +15 -2
- package/dist/storage/node-fs.d.ts +19 -3
- package/dist/storage/root.d.ts +2 -0
- package/dist/storage/types.d.ts +63 -1
- package/dist/types.d.ts +422 -11
- package/dist/utils/page-token.d.ts +60 -0
- package/dist/utils.d.ts +1 -1
- package/package.json +14 -44
- package/dist/browser.es.js +0 -158
- package/dist/client-D2GRjxRE.mjs +0 -927
- package/dist/index.es.js +0 -140
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# modjules - the agent-ready SDK for Jules
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Status: Useful tool but still experimental. Supported and moving fast to improve.
|
|
4
4
|
|
|
5
5
|
## Making Jules Agent-Ready
|
|
6
6
|
|
|
@@ -59,7 +59,7 @@ Process multiple items in parallel with `jules.all()`. This method is designed t
|
|
|
59
59
|
```javascript
|
|
60
60
|
const todos = ['Fix login bug', 'Update README', 'Refactor tests'];
|
|
61
61
|
|
|
62
|
-
// Processes items concurrently (default:
|
|
62
|
+
// Processes items concurrently (default: 3 at a time)
|
|
63
63
|
const sessions = await jules.all(todos, (task) => ({
|
|
64
64
|
prompt: task,
|
|
65
65
|
source: { github: 'user/repo', branch: 'main' },
|
|
@@ -121,16 +121,20 @@ const session = await jules.session({
|
|
|
121
121
|
|
|
122
122
|
When used in a browser environment (e.g., in a web application bundled with Vite, Webpack, or Rollup), the SDK automatically uses a browser-specific implementation that leverages IndexedDB for storage. This allows your web application to maintain session state locally.
|
|
123
123
|
|
|
124
|
-
> **
|
|
124
|
+
> **TEST ONLY DO NOT USE IN PRODUCTION:** The browser module is designed for testing and prototyping only. Never expose your `JULES_API_KEY` in a production application.
|
|
125
125
|
|
|
126
|
-
To use the browser version, you can explicitly import it:
|
|
126
|
+
To use the browser version, you can explicitly import it and must configure it with the test-only API key option:
|
|
127
127
|
|
|
128
128
|
```typescript
|
|
129
129
|
// Explicitly import the browser-optimized version
|
|
130
130
|
import { jules } from 'modjules/browser';
|
|
131
131
|
|
|
132
|
-
//
|
|
133
|
-
const
|
|
132
|
+
// Initialize with the test-only option
|
|
133
|
+
const testJules = jules.with({
|
|
134
|
+
apiKey_TEST_ONLY_DO_NOT_USE_IN_PRODUCTION: '...',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const session = await testJules.session({
|
|
134
138
|
prompt: 'Refactor the user authentication module.',
|
|
135
139
|
source: { github: 'your-org/your-repo', branch: 'develop' },
|
|
136
140
|
});
|
|
@@ -24,9 +24,52 @@ export declare class DefaultActivityClient implements ActivityClient {
|
|
|
24
24
|
private network;
|
|
25
25
|
constructor(storage: ActivityStorage, network: NetworkClient);
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Re-hydrates plain artifact objects from storage into rich class instances.
|
|
28
|
+
* JSON serialization loses class information (methods), so we need to restore it.
|
|
29
|
+
*
|
|
30
|
+
* **Behavior:**
|
|
31
|
+
* - Iterates through artifacts in an activity.
|
|
32
|
+
* - If an artifact is a plain object (not a class instance), it's re-instantiated.
|
|
33
|
+
* - Handles backward compatibility: if an artifact is already a class instance, it's skipped.
|
|
34
|
+
*
|
|
35
|
+
* @param activity The activity from storage, potentially with plain artifacts.
|
|
36
|
+
* @returns The same activity with its artifacts guaranteed to be class instances.
|
|
37
|
+
*/
|
|
38
|
+
private _hydrateActivityArtifacts;
|
|
39
|
+
/**
|
|
40
|
+
* Returns an async iterable of all activities.
|
|
41
|
+
*
|
|
42
|
+
* **Behavior:**
|
|
43
|
+
* - Always syncs new activities from the network first (via hydrate).
|
|
44
|
+
* - Then yields all activities from local storage.
|
|
45
|
+
*
|
|
46
|
+
* This ensures callers always get the complete, up-to-date history
|
|
47
|
+
* rather than potentially stale cached data.
|
|
28
48
|
*/
|
|
29
49
|
history(): AsyncIterable<Activity>;
|
|
50
|
+
/**
|
|
51
|
+
* Fetches all activities from the network and caches them.
|
|
52
|
+
* Used to populate an empty cache.
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
private fetchAndCacheAll;
|
|
56
|
+
/**
|
|
57
|
+
* Syncs new activities from the network to local cache.
|
|
58
|
+
*
|
|
59
|
+
* **Optimization Strategy:**
|
|
60
|
+
* Activities are immutable - once downloaded, they never change.
|
|
61
|
+
* We use the Jules API's pageToken (nanosecond timestamp) to fetch
|
|
62
|
+
* only activities newer than our latest cached one.
|
|
63
|
+
*
|
|
64
|
+
* **Behavior:**
|
|
65
|
+
* - Empty cache: Fetches all activities (no pageToken)
|
|
66
|
+
* - Has cached activities: Constructs pageToken from latest createTime,
|
|
67
|
+
* fetches only newer activities
|
|
68
|
+
* - Frozen session (> 30 days): Skips API call entirely
|
|
69
|
+
*
|
|
70
|
+
* @returns The number of new activities synced.
|
|
71
|
+
*/
|
|
72
|
+
hydrate(): Promise<number>;
|
|
30
73
|
/**
|
|
31
74
|
* Returns an async iterable of new activities from the network.
|
|
32
75
|
* This method polls the network and updates the local storage.
|
|
@@ -14,6 +14,7 @@ export interface SelectOptions {
|
|
|
14
14
|
before?: string;
|
|
15
15
|
type?: string;
|
|
16
16
|
limit?: number;
|
|
17
|
+
order?: 'asc' | 'desc';
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Interface for managing session activities.
|
|
@@ -53,4 +54,10 @@ export interface ActivityClient {
|
|
|
53
54
|
* NETWORK GET: Fetches a specific activity from the network and caches it.
|
|
54
55
|
*/
|
|
55
56
|
get(activityId: string): Promise<Activity>;
|
|
57
|
+
/**
|
|
58
|
+
* NETWORK SYNC: Fetches all activities from the network and caches them.
|
|
59
|
+
* Useful when you suspect the cache is stale.
|
|
60
|
+
* @returns The number of activities synced.
|
|
61
|
+
*/
|
|
62
|
+
hydrate(): Promise<number>;
|
|
56
63
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Activity, ActivitySummary } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a concise summary for an activity.
|
|
4
|
+
* @param activity The activity to summarize.
|
|
5
|
+
* @returns A summary of the activity.
|
|
6
|
+
*/
|
|
7
|
+
export declare function toSummary(activity: Activity): ActivitySummary;
|
package/dist/api.d.ts
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
|
+
import { ProxyConfig } from './types.js';
|
|
2
|
+
export type RateLimitRetryConfig = {
|
|
3
|
+
maxRetryTimeMs: number;
|
|
4
|
+
baseDelayMs: number;
|
|
5
|
+
maxDelayMs: number;
|
|
6
|
+
};
|
|
1
7
|
export type ApiClientOptions = {
|
|
2
8
|
apiKey: string | undefined;
|
|
3
9
|
baseUrl: string;
|
|
4
10
|
requestTimeoutMs: number;
|
|
11
|
+
proxy?: ProxyConfig;
|
|
12
|
+
rateLimitRetry?: Partial<RateLimitRetryConfig>;
|
|
13
|
+
};
|
|
14
|
+
export type HandshakeContext = {
|
|
15
|
+
intent: 'create';
|
|
16
|
+
sessionConfig: any;
|
|
17
|
+
} | {
|
|
18
|
+
intent: 'resume';
|
|
19
|
+
sessionId: string;
|
|
5
20
|
};
|
|
6
21
|
export type ApiRequestOptions = {
|
|
7
22
|
method?: 'GET' | 'POST';
|
|
8
23
|
body?: Record<string, unknown>;
|
|
9
|
-
|
|
24
|
+
query?: Record<string, any>;
|
|
25
|
+
headers?: Record<string, string>;
|
|
26
|
+
handshake?: HandshakeContext;
|
|
27
|
+
_isRetry?: boolean;
|
|
10
28
|
};
|
|
11
29
|
/**
|
|
12
30
|
* A simple internal API client to handle HTTP requests to the Jules API.
|
|
@@ -16,6 +34,18 @@ export declare class ApiClient {
|
|
|
16
34
|
private readonly apiKey;
|
|
17
35
|
private readonly baseUrl;
|
|
18
36
|
private readonly requestTimeoutMs;
|
|
37
|
+
private readonly proxy?;
|
|
38
|
+
private readonly rateLimitConfig;
|
|
39
|
+
private capabilityToken;
|
|
40
|
+
private handshakePromise;
|
|
19
41
|
constructor(options: ApiClientOptions);
|
|
20
42
|
request<T>(endpoint: string, options?: ApiRequestOptions): Promise<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Ensures we have a valid Capability Token.
|
|
45
|
+
* If not, performs the Handshake.
|
|
46
|
+
*/
|
|
47
|
+
private ensureToken;
|
|
48
|
+
private performHandshake;
|
|
49
|
+
private resolveUrl;
|
|
50
|
+
private fetchWithTimeout;
|
|
21
51
|
}
|
package/dist/artifacts.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RestMediaArtifact, RestBashOutputArtifact } from './types.js';
|
|
1
|
+
import { RestMediaArtifact, RestBashOutputArtifact, GitPatch, ParsedChangeSet } from './types.js';
|
|
2
2
|
import { Platform } from './platform/types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Represents a media artifact (e.g. image) produced by an activity.
|
|
@@ -52,3 +52,24 @@ export declare class BashArtifact {
|
|
|
52
52
|
*/
|
|
53
53
|
toString(): string;
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Represents a set of code changes (unified diff) produced by an activity.
|
|
57
|
+
* Provides a helper method to parse the diff into structured data.
|
|
58
|
+
*/
|
|
59
|
+
export declare class ChangeSetArtifact {
|
|
60
|
+
readonly type: "changeSet";
|
|
61
|
+
readonly source: string;
|
|
62
|
+
readonly gitPatch: GitPatch;
|
|
63
|
+
constructor(source: string, gitPatch: GitPatch);
|
|
64
|
+
/**
|
|
65
|
+
* Parses the unified diff and returns structured file change information.
|
|
66
|
+
*
|
|
67
|
+
* **Data Transformation:**
|
|
68
|
+
* - Extracts file paths from diff headers.
|
|
69
|
+
* - Determines change type (created/modified/deleted) from /dev/null markers.
|
|
70
|
+
* - Counts additions (+) and deletions (-) in hunks.
|
|
71
|
+
*
|
|
72
|
+
* @returns Parsed diff with file paths, change types, and line counts.
|
|
73
|
+
*/
|
|
74
|
+
parsed(): ParsedChangeSet;
|
|
75
|
+
}
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import { JulesClient } from './types.js';
|
|
1
|
+
import { JulesClient, JulesOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Connects to the Jules service with the provided configuration.
|
|
4
|
+
* Acts as a factory method for creating a new client instance.
|
|
5
|
+
*
|
|
6
|
+
* @param options Configuration options for the client.
|
|
7
|
+
* @returns A new JulesClient instance.
|
|
8
|
+
*/
|
|
9
|
+
export declare function connect(options?: JulesOptions): JulesClient;
|
|
2
10
|
/**
|
|
3
11
|
* The main entry point for the Jules SDK for browser environments.
|
|
4
12
|
* This is a pre-initialized client that can be used immediately with default settings.
|
package/dist/browser.mjs
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { J as JulesClientImpl, a as MemorySessionStorage } from "./memory-DE2Wujcu.js";
|
|
2
|
+
import { A, I, d, e, b, c, f, h, i, j } from "./memory-DE2Wujcu.js";
|
|
3
|
+
import { openDB } from "idb";
|
|
4
|
+
const DB_NAME$1 = "jules-activities";
|
|
5
|
+
const STORE_NAME = "activities";
|
|
6
|
+
class BrowserStorage {
|
|
7
|
+
sessionId;
|
|
8
|
+
dbPromise = null;
|
|
9
|
+
constructor(sessionId) {
|
|
10
|
+
this.sessionId = sessionId;
|
|
11
|
+
}
|
|
12
|
+
getDb() {
|
|
13
|
+
if (!this.dbPromise) {
|
|
14
|
+
this.dbPromise = openDB(DB_NAME$1, 2, {
|
|
15
|
+
upgrade(db, oldVersion, newVersion, transaction) {
|
|
16
|
+
if (oldVersion < 1) {
|
|
17
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
18
|
+
const store = db.createObjectStore(STORE_NAME, {
|
|
19
|
+
keyPath: "id"
|
|
20
|
+
});
|
|
21
|
+
store.createIndex("sessionTimestamp", [
|
|
22
|
+
"sessionId",
|
|
23
|
+
"createTime"
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!db.objectStoreNames.contains("artifacts")) {
|
|
28
|
+
const store = db.createObjectStore("artifacts", {
|
|
29
|
+
keyPath: "filepath"
|
|
30
|
+
});
|
|
31
|
+
store.createIndex("activityId", "activityId");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return this.dbPromise;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Initializes the storage.
|
|
40
|
+
*
|
|
41
|
+
* **Side Effects:**
|
|
42
|
+
* - Opens an IndexedDB connection.
|
|
43
|
+
* - Upgrades the database schema to v2 if necessary (creating object stores).
|
|
44
|
+
*/
|
|
45
|
+
async init() {
|
|
46
|
+
await this.getDb();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Closes the storage connection.
|
|
50
|
+
*/
|
|
51
|
+
async close() {
|
|
52
|
+
if (this.dbPromise) {
|
|
53
|
+
const db = await this.dbPromise;
|
|
54
|
+
db.close();
|
|
55
|
+
this.dbPromise = null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Appends an activity to IndexedDB.
|
|
60
|
+
*
|
|
61
|
+
* **Side Effects:**
|
|
62
|
+
* - Adds a `sessionId` field to the activity for indexing.
|
|
63
|
+
* - Writes the modified activity to the `activities` object store.
|
|
64
|
+
*/
|
|
65
|
+
async append(activity) {
|
|
66
|
+
const db = await this.getDb();
|
|
67
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
68
|
+
const store = tx.objectStore(STORE_NAME);
|
|
69
|
+
const storableActivity = { ...activity, sessionId: this.sessionId };
|
|
70
|
+
await store.put(storableActivity);
|
|
71
|
+
await tx.done;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Retrieves an activity by ID.
|
|
75
|
+
*/
|
|
76
|
+
async get(activityId) {
|
|
77
|
+
const db = await this.getDb();
|
|
78
|
+
const activity = await db.get(STORE_NAME, activityId);
|
|
79
|
+
if (activity) {
|
|
80
|
+
delete activity.sessionId;
|
|
81
|
+
}
|
|
82
|
+
return activity;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Retrieves the latest activity for the current session.
|
|
86
|
+
*
|
|
87
|
+
* **Logic:**
|
|
88
|
+
* - Uses the `sessionTimestamp` index to query efficiently.
|
|
89
|
+
* - Opens a cursor in 'prev' direction to find the last entry first.
|
|
90
|
+
*/
|
|
91
|
+
async latest() {
|
|
92
|
+
const db = await this.getDb();
|
|
93
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
94
|
+
const store = tx.objectStore(STORE_NAME);
|
|
95
|
+
const index = store.index("sessionTimestamp");
|
|
96
|
+
const range = IDBKeyRange.bound(
|
|
97
|
+
[this.sessionId, ""],
|
|
98
|
+
[this.sessionId, (/* @__PURE__ */ new Date(864e13)).toISOString()]
|
|
99
|
+
);
|
|
100
|
+
const cursor = await index.openCursor(range, "prev");
|
|
101
|
+
if (!cursor) {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
const activity = cursor.value;
|
|
105
|
+
if (activity) {
|
|
106
|
+
delete activity.sessionId;
|
|
107
|
+
}
|
|
108
|
+
return activity;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Yields all activities for the current session.
|
|
112
|
+
*/
|
|
113
|
+
async *scan() {
|
|
114
|
+
const db = await this.getDb();
|
|
115
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
116
|
+
const store = tx.objectStore(STORE_NAME);
|
|
117
|
+
const index = store.index("sessionTimestamp");
|
|
118
|
+
const range = IDBKeyRange.bound(
|
|
119
|
+
[this.sessionId, ""],
|
|
120
|
+
[this.sessionId, (/* @__PURE__ */ new Date(864e13)).toISOString()]
|
|
121
|
+
);
|
|
122
|
+
let cursor = await index.openCursor(range, "next");
|
|
123
|
+
while (cursor) {
|
|
124
|
+
const activity = cursor.value;
|
|
125
|
+
if (activity) {
|
|
126
|
+
delete activity.sessionId;
|
|
127
|
+
}
|
|
128
|
+
yield activity;
|
|
129
|
+
cursor = await cursor.continue();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
|
|
134
|
+
const DB_NAME = "jules-activities";
|
|
135
|
+
const ARTIFACTS_STORE_NAME = "artifacts";
|
|
136
|
+
const ACTIVITIES_STORE_NAME = "activities";
|
|
137
|
+
class BrowserPlatform {
|
|
138
|
+
dbPromise = null;
|
|
139
|
+
getDb() {
|
|
140
|
+
if (!this.dbPromise) {
|
|
141
|
+
this.dbPromise = openDB(DB_NAME, 2, {
|
|
142
|
+
upgrade(db, oldVersion, newVersion, transaction) {
|
|
143
|
+
if (!db.objectStoreNames.contains(ACTIVITIES_STORE_NAME)) {
|
|
144
|
+
const store = db.createObjectStore(ACTIVITIES_STORE_NAME, {
|
|
145
|
+
keyPath: "id"
|
|
146
|
+
});
|
|
147
|
+
store.createIndex("sessionTimestamp", ["sessionId", "createTime"]);
|
|
148
|
+
}
|
|
149
|
+
if (!db.objectStoreNames.contains(ARTIFACTS_STORE_NAME)) {
|
|
150
|
+
const store = db.createObjectStore(ARTIFACTS_STORE_NAME, {
|
|
151
|
+
keyPath: "filepath"
|
|
152
|
+
});
|
|
153
|
+
store.createIndex("activityId", "activityId");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return this.dbPromise;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Saves a file to IndexedDB.
|
|
162
|
+
*
|
|
163
|
+
* **Data Transformation:**
|
|
164
|
+
* - Decodes base64 data into a `Blob`.
|
|
165
|
+
*
|
|
166
|
+
* **Side Effects:**
|
|
167
|
+
* - Stores the blob in the `artifacts` object store.
|
|
168
|
+
* - Associates the file with the `activityId` (if provided).
|
|
169
|
+
*
|
|
170
|
+
* @throws {Error} If the encoding is not 'base64'.
|
|
171
|
+
*/
|
|
172
|
+
async saveFile(filepath, data, encoding, activityId) {
|
|
173
|
+
if (encoding !== "base64") {
|
|
174
|
+
throw new Error(`Unsupported encoding for browser saveFile: ${encoding}`);
|
|
175
|
+
}
|
|
176
|
+
const db = await this.getDb();
|
|
177
|
+
const blob = this.base64ToBlob(data);
|
|
178
|
+
await db.put(ARTIFACTS_STORE_NAME, {
|
|
179
|
+
filepath,
|
|
180
|
+
blob,
|
|
181
|
+
activityId,
|
|
182
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
async sleep(ms) {
|
|
186
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
187
|
+
}
|
|
188
|
+
createDataUrl(data, mimeType) {
|
|
189
|
+
return `data:${mimeType};base64,${data}`;
|
|
190
|
+
}
|
|
191
|
+
base64ToBlob(data, mimeType) {
|
|
192
|
+
const byteCharacters = atob(data);
|
|
193
|
+
const byteNumbers = new Array(byteCharacters.length);
|
|
194
|
+
for (let i2 = 0; i2 < byteCharacters.length; i2++) {
|
|
195
|
+
byteNumbers[i2] = byteCharacters.charCodeAt(i2);
|
|
196
|
+
}
|
|
197
|
+
const byteArray = new Uint8Array(byteNumbers);
|
|
198
|
+
return new Blob([byteArray], mimeType ? { type: mimeType } : void 0);
|
|
199
|
+
}
|
|
200
|
+
async fetch(input, init) {
|
|
201
|
+
const res = await window.fetch(input, init);
|
|
202
|
+
return {
|
|
203
|
+
ok: res.ok,
|
|
204
|
+
status: res.status,
|
|
205
|
+
json: () => res.json(),
|
|
206
|
+
text: () => res.text()
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
crypto = {
|
|
210
|
+
randomUUID: () => self.crypto.randomUUID(),
|
|
211
|
+
async sign(text, secret) {
|
|
212
|
+
const enc = new TextEncoder();
|
|
213
|
+
const key = await window.crypto.subtle.importKey(
|
|
214
|
+
"raw",
|
|
215
|
+
enc.encode(secret),
|
|
216
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
217
|
+
false,
|
|
218
|
+
["sign"]
|
|
219
|
+
);
|
|
220
|
+
const signature = await window.crypto.subtle.sign(
|
|
221
|
+
"HMAC",
|
|
222
|
+
key,
|
|
223
|
+
enc.encode(text)
|
|
224
|
+
);
|
|
225
|
+
return this.arrayBufferToBase64Url(signature);
|
|
226
|
+
},
|
|
227
|
+
async verify(text, signature, secret) {
|
|
228
|
+
const expected = await this.sign(text, secret);
|
|
229
|
+
return expected === signature;
|
|
230
|
+
},
|
|
231
|
+
// Helper for Base64URL encoding in browser
|
|
232
|
+
arrayBufferToBase64Url(buffer) {
|
|
233
|
+
const bytes = new Uint8Array(buffer);
|
|
234
|
+
let binary = "";
|
|
235
|
+
for (let i2 = 0; i2 < bytes.byteLength; i2++) {
|
|
236
|
+
binary += String.fromCharCode(bytes[i2]);
|
|
237
|
+
}
|
|
238
|
+
return window.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
encoding = {
|
|
242
|
+
base64Encode: (text) => {
|
|
243
|
+
const encoder = new TextEncoder();
|
|
244
|
+
const bytes = encoder.encode(text);
|
|
245
|
+
let binary = "";
|
|
246
|
+
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
247
|
+
binary += String.fromCharCode(bytes[i2]);
|
|
248
|
+
}
|
|
249
|
+
return window.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
250
|
+
},
|
|
251
|
+
base64Decode: (text) => {
|
|
252
|
+
const base64 = text.replace(/-/g, "+").replace(/_/g, "/");
|
|
253
|
+
const binary = window.atob(base64);
|
|
254
|
+
const bytes = new Uint8Array(binary.length);
|
|
255
|
+
for (let i2 = 0; i2 < binary.length; i2++) {
|
|
256
|
+
bytes[i2] = binary.charCodeAt(i2);
|
|
257
|
+
}
|
|
258
|
+
const decoder = new TextDecoder();
|
|
259
|
+
return decoder.decode(bytes);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
getEnv(key) {
|
|
263
|
+
if (typeof import.meta !== "undefined" && __vite_import_meta_env__ && __vite_import_meta_env__[key]) {
|
|
264
|
+
return __vite_import_meta_env__[key];
|
|
265
|
+
}
|
|
266
|
+
const globalRef = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof self !== "undefined" ? self : {};
|
|
267
|
+
const anyGlobal = globalRef;
|
|
268
|
+
try {
|
|
269
|
+
if (typeof process !== "undefined" && process.env && process.env[key]) {
|
|
270
|
+
return process.env[key];
|
|
271
|
+
}
|
|
272
|
+
} catch (e2) {
|
|
273
|
+
}
|
|
274
|
+
if (anyGlobal.__MODJULES__ && anyGlobal.__MODJULES__[key]) {
|
|
275
|
+
return anyGlobal.__MODJULES__[key];
|
|
276
|
+
}
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const defaultPlatform = new BrowserPlatform();
|
|
281
|
+
const defaultStorageFactory = {
|
|
282
|
+
activity: (sessionId) => new BrowserStorage(sessionId),
|
|
283
|
+
session: () => new MemorySessionStorage()
|
|
284
|
+
// Use Memory for now, upgrade to IndexedDB later
|
|
285
|
+
};
|
|
286
|
+
function connect(options = {}) {
|
|
287
|
+
return new JulesClientImpl(options, defaultStorageFactory, defaultPlatform);
|
|
288
|
+
}
|
|
289
|
+
const jules = connect();
|
|
290
|
+
export {
|
|
291
|
+
A as AutomatedSessionFailedError,
|
|
292
|
+
I as InvalidStateError,
|
|
293
|
+
d as JulesApiError,
|
|
294
|
+
e as JulesAuthenticationError,
|
|
295
|
+
b as JulesError,
|
|
296
|
+
c as JulesNetworkError,
|
|
297
|
+
f as JulesRateLimitError,
|
|
298
|
+
h as MissingApiKeyError,
|
|
299
|
+
i as SourceNotFoundError,
|
|
300
|
+
j as SyncInProgressError,
|
|
301
|
+
connect,
|
|
302
|
+
jules
|
|
303
|
+
};
|
|
304
|
+
//# sourceMappingURL=browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.mjs","sources":["../src/storage/browser.ts","../src/platform/browser.ts","../src/browser.ts"],"sourcesContent":["import { openDB, IDBPDatabase } from 'idb';\nimport { Activity } from '../types.js';\nimport { ActivityStorage } from './types.js';\n\nconst DB_NAME = 'jules-activities';\nconst STORE_NAME = 'activities';\n\n/**\n * Browser implementation of ActivityStorage using IndexedDB.\n * Allows for persistent storage of activities in the browser.\n */\nexport class BrowserStorage implements ActivityStorage {\n private sessionId: string;\n private dbPromise: Promise<IDBPDatabase<unknown>> | null = null;\n\n constructor(sessionId: string) {\n this.sessionId = sessionId;\n }\n\n private getDb(): Promise<IDBPDatabase<unknown>> {\n if (!this.dbPromise) {\n // We use version 2 here as well to match BrowserPlatform and avoid conflicts.\n // We don't necessarily need to know about 'artifacts' store here, but we must use the same version.\n this.dbPromise = openDB(DB_NAME, 2, {\n upgrade(db, oldVersion, newVersion, transaction) {\n if (oldVersion < 1) {\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n const store = db.createObjectStore(STORE_NAME, {\n keyPath: 'id',\n });\n // Index to efficiently find the latest activity for a session\n store.createIndex('sessionTimestamp', [\n 'sessionId',\n 'createTime',\n ]);\n }\n }\n // Ensure artifacts store exists if we are upgrading to v2 or from scratch\n // This might duplicate logic in BrowserPlatform, but it's safer if both can upgrade.\n if (!db.objectStoreNames.contains('artifacts')) {\n const store = db.createObjectStore('artifacts', {\n keyPath: 'filepath',\n });\n store.createIndex('activityId', 'activityId');\n }\n },\n });\n }\n return this.dbPromise;\n }\n\n /**\n * Initializes the storage.\n *\n * **Side Effects:**\n * - Opens an IndexedDB connection.\n * - Upgrades the database schema to v2 if necessary (creating object stores).\n */\n async init(): Promise<void> {\n // openDB handles initialization, so just call it to ensure DB is ready.\n await this.getDb();\n }\n\n /**\n * Closes the storage connection.\n */\n async close(): Promise<void> {\n if (this.dbPromise) {\n const db = await this.dbPromise;\n db.close();\n this.dbPromise = null;\n }\n }\n\n /**\n * Appends an activity to IndexedDB.\n *\n * **Side Effects:**\n * - Adds a `sessionId` field to the activity for indexing.\n * - Writes the modified activity to the `activities` object store.\n */\n async append(activity: Activity): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n // Add sessionId to the object for indexing\n const storableActivity = { ...activity, sessionId: this.sessionId };\n await store.put(storableActivity);\n await tx.done;\n }\n\n /**\n * Retrieves an activity by ID.\n */\n async get(activityId: string): Promise<Activity | undefined> {\n const db = await this.getDb();\n const activity = await db.get(STORE_NAME, activityId);\n // Strip sessionId before returning\n if (activity) {\n delete (activity as any).sessionId;\n }\n return activity as Activity | undefined;\n }\n\n /**\n * Retrieves the latest activity for the current session.\n *\n * **Logic:**\n * - Uses the `sessionTimestamp` index to query efficiently.\n * - Opens a cursor in 'prev' direction to find the last entry first.\n */\n async latest(): Promise<Activity | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(STORE_NAME, 'readonly');\n const store = tx.objectStore(STORE_NAME);\n const index = store.index('sessionTimestamp');\n\n // Create a key range for just this session\n const range = IDBKeyRange.bound(\n [this.sessionId, ''],\n [this.sessionId, new Date(8640000000000000).toISOString()],\n );\n\n const cursor = await index.openCursor(range, 'prev');\n if (!cursor) {\n return undefined;\n }\n const activity = cursor.value;\n // Strip sessionId before returning\n if (activity) {\n delete (activity as any).sessionId;\n }\n return activity as Activity | undefined;\n }\n\n /**\n * Yields all activities for the current session.\n */\n async *scan(): AsyncIterable<Activity> {\n const db = await this.getDb();\n const tx = db.transaction(STORE_NAME, 'readonly');\n const store = tx.objectStore(STORE_NAME);\n const index = store.index('sessionTimestamp');\n\n const range = IDBKeyRange.bound(\n [this.sessionId, ''],\n [this.sessionId, new Date(8640000000000000).toISOString()],\n );\n\n let cursor = await index.openCursor(range, 'next');\n\n while (cursor) {\n const activity = cursor.value;\n if (activity) {\n delete (activity as any).sessionId;\n }\n yield activity as Activity;\n cursor = await cursor.continue();\n }\n }\n}\n","import { openDB, IDBPDatabase } from 'idb';\nimport { Platform, PlatformResponse } from './types.js';\n\nconst DB_NAME = 'jules-activities';\nconst ARTIFACTS_STORE_NAME = 'artifacts';\nconst ACTIVITIES_STORE_NAME = 'activities';\n\n/**\n * Browser implementation of the Platform interface.\n * Uses IndexedDB for file storage.\n */\nexport class BrowserPlatform implements Platform {\n private dbPromise: Promise<IDBPDatabase<unknown>> | null = null;\n\n private getDb(): Promise<IDBPDatabase<unknown>> {\n if (!this.dbPromise) {\n this.dbPromise = openDB(DB_NAME, 2, {\n upgrade(db, oldVersion, newVersion, transaction) {\n // Ensure activities store exists (copied from BrowserStorage to avoid race conditions)\n if (!db.objectStoreNames.contains(ACTIVITIES_STORE_NAME)) {\n const store = db.createObjectStore(ACTIVITIES_STORE_NAME, {\n keyPath: 'id',\n });\n store.createIndex('sessionTimestamp', ['sessionId', 'createTime']);\n }\n // Ensure artifacts store exists\n if (!db.objectStoreNames.contains(ARTIFACTS_STORE_NAME)) {\n const store = db.createObjectStore(ARTIFACTS_STORE_NAME, {\n keyPath: 'filepath',\n });\n store.createIndex('activityId', 'activityId');\n }\n },\n });\n }\n return this.dbPromise;\n }\n\n /**\n * Saves a file to IndexedDB.\n *\n * **Data Transformation:**\n * - Decodes base64 data into a `Blob`.\n *\n * **Side Effects:**\n * - Stores the blob in the `artifacts` object store.\n * - Associates the file with the `activityId` (if provided).\n *\n * @throws {Error} If the encoding is not 'base64'.\n */\n async saveFile(\n filepath: string,\n data: string,\n encoding: 'base64',\n activityId?: string,\n ): Promise<void> {\n if (encoding !== 'base64') {\n throw new Error(`Unsupported encoding for browser saveFile: ${encoding}`);\n }\n const db = await this.getDb();\n const blob = this.base64ToBlob(data);\n\n await db.put(ARTIFACTS_STORE_NAME, {\n filepath,\n blob,\n activityId,\n createdAt: new Date().toISOString(),\n });\n }\n\n async sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n createDataUrl(data: string, mimeType: string): string {\n return `data:${mimeType};base64,${data}`;\n }\n\n private base64ToBlob(data: string, mimeType?: string): Blob {\n const byteCharacters = atob(data);\n const byteNumbers = new Array(byteCharacters.length);\n for (let i = 0; i < byteCharacters.length; i++) {\n byteNumbers[i] = byteCharacters.charCodeAt(i);\n }\n const byteArray = new Uint8Array(byteNumbers);\n return new Blob([byteArray], mimeType ? { type: mimeType } : undefined);\n }\n\n async fetch(input: string, init?: any): Promise<PlatformResponse> {\n const res = await window.fetch(input, init);\n return {\n ok: res.ok,\n status: res.status,\n json: () => res.json(),\n text: () => res.text(),\n };\n }\n\n crypto = {\n randomUUID: () => self.crypto.randomUUID(),\n\n async sign(text: string, secret: string): Promise<string> {\n const enc = new TextEncoder();\n const key = await window.crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n const signature = await window.crypto.subtle.sign(\n 'HMAC',\n key,\n enc.encode(text),\n );\n return this.arrayBufferToBase64Url(signature);\n },\n\n async verify(\n text: string,\n signature: string,\n secret: string,\n ): Promise<boolean> {\n const expected = await this.sign(text, secret);\n return expected === signature;\n },\n\n // Helper for Base64URL encoding in browser\n arrayBufferToBase64Url(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window\n .btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n },\n };\n\n encoding = {\n base64Encode: (text: string): string => {\n // Use TextEncoder for proper UTF-8 handling before Base64\n const encoder = new TextEncoder();\n const bytes = encoder.encode(text);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window\n .btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n },\n\n base64Decode: (text: string): string => {\n const base64 = text.replace(/-/g, '+').replace(/_/g, '/');\n // Standard atob handles the Base64 decode, then we must interpret the bytes as UTF-8\n const binary = window.atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n const decoder = new TextDecoder();\n return decoder.decode(bytes);\n },\n };\n\n getEnv(key: string): string | undefined {\n // 1. Vite / Modern ESM Support\n if (\n typeof import.meta !== 'undefined' &&\n (import.meta as any).env &&\n (import.meta as any).env[key]\n ) {\n return (import.meta as any).env[key];\n }\n\n // 2. Safe Global Fallbacks (window, self, globalThis)\n const globalRef =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof window !== 'undefined'\n ? window\n : typeof self !== 'undefined'\n ? self\n : {};\n const anyGlobal = globalRef as any;\n\n // 3. Legacy process.env check (Safe)\n // We strictly check for existence to avoid ReferenceError if 'process' is missing.\n try {\n if (typeof process !== 'undefined' && process.env && process.env[key]) {\n return process.env[key];\n }\n } catch (e) {\n // Ignore ReferenceError if process is not defined\n }\n\n // 4. Manual Injection Fallback\n if (anyGlobal.__MODJULES__ && anyGlobal.__MODJULES__[key]) {\n return anyGlobal.__MODJULES__[key];\n }\n\n return undefined;\n }\n}\n","// src/browser.ts\nimport { JulesClientImpl } from './client.js';\nimport { BrowserStorage } from './storage/browser.js';\nimport { MemorySessionStorage } from './storage/memory.js';\nimport { BrowserPlatform } from './platform/browser.js';\nimport { JulesClient, JulesOptions, StorageFactory } from './types.js';\n\nconst defaultPlatform = new BrowserPlatform();\nconst defaultStorageFactory: StorageFactory = {\n activity: (sessionId: string) => new BrowserStorage(sessionId),\n session: () => new MemorySessionStorage(), // Use Memory for now, upgrade to IndexedDB later\n};\n\n/**\n * Connects to the Jules service with the provided configuration.\n * Acts as a factory method for creating a new client instance.\n *\n * @param options Configuration options for the client.\n * @returns A new JulesClient instance.\n */\nexport function connect(options: JulesOptions = {}): JulesClient {\n return new JulesClientImpl(options, defaultStorageFactory, defaultPlatform);\n}\n\n/**\n * The main entry point for the Jules SDK for browser environments.\n * This is a pre-initialized client that can be used immediately with default settings.\n *\n * @example\n * import { jules } from 'modjules/browser';\n * const session = await jules.session({ ... });\n */\nexport const jules: JulesClient = connect();\n\n// Re-export all the types for convenience\nexport * from './errors.js';\nexport type {\n Activity,\n ActivityAgentMessaged,\n ActivityPlanApproved,\n ActivityPlanGenerated,\n ActivityProgressUpdated,\n ActivitySessionCompleted,\n ActivitySessionFailed,\n ActivityUserMessaged,\n Artifact,\n AutomatedSession,\n BashArtifact,\n ChangeSet,\n GitHubRepo,\n GitPatch,\n JulesClient,\n JulesOptions,\n MediaArtifact,\n Outcome,\n Plan,\n PlanStep,\n PullRequest,\n SessionClient,\n SessionConfig,\n SessionOutput,\n SessionResource,\n SessionState,\n Source,\n SourceContext,\n SourceInput,\n SourceManager,\n} from './types.js';\n"],"names":["DB_NAME","i","e"],"mappings":";;;AAIA,MAAMA,YAAU;AAChB,MAAM,aAAa;AAMZ,MAAM,eAA0C;AAAA,EAC7C;AAAA,EACA,YAAmD;AAAA,EAE3D,YAAY,WAAmB;AAC7B,SAAK,YAAY;AAAA,EACnB;AAAA,EAEQ,QAAwC;AAC9C,QAAI,CAAC,KAAK,WAAW;AAGnB,WAAK,YAAY,OAAOA,WAAS,GAAG;AAAA,QAClC,QAAQ,IAAI,YAAY,YAAY,aAAa;AAC/C,cAAI,aAAa,GAAG;AAClB,gBAAI,CAAC,GAAG,iBAAiB,SAAS,UAAU,GAAG;AAC7C,oBAAM,QAAQ,GAAG,kBAAkB,YAAY;AAAA,gBAC7C,SAAS;AAAA,cAAA,CACV;AAED,oBAAM,YAAY,oBAAoB;AAAA,gBACpC;AAAA,gBACA;AAAA,cAAA,CACD;AAAA,YACH;AAAA,UACF;AAGA,cAAI,CAAC,GAAG,iBAAiB,SAAS,WAAW,GAAG;AAC9C,kBAAM,QAAQ,GAAG,kBAAkB,aAAa;AAAA,cAC9C,SAAS;AAAA,YAAA,CACV;AACD,kBAAM,YAAY,cAAc,YAAY;AAAA,UAC9C;AAAA,QACF;AAAA,MAAA,CACD;AAAA,IACH;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAsB;AAE1B,UAAM,KAAK,MAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,QAAI,KAAK,WAAW;AAClB,YAAM,KAAK,MAAM,KAAK;AACtB,SAAG,MAAA;AACH,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAO,UAAmC;AAC9C,UAAM,KAAK,MAAM,KAAK,MAAA;AACtB,UAAM,KAAK,GAAG,YAAY,YAAY,WAAW;AACjD,UAAM,QAAQ,GAAG,YAAY,UAAU;AAEvC,UAAM,mBAAmB,EAAE,GAAG,UAAU,WAAW,KAAK,UAAA;AACxD,UAAM,MAAM,IAAI,gBAAgB;AAChC,UAAM,GAAG;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,YAAmD;AAC3D,UAAM,KAAK,MAAM,KAAK,MAAA;AACtB,UAAM,WAAW,MAAM,GAAG,IAAI,YAAY,UAAU;AAEpD,QAAI,UAAU;AACZ,aAAQ,SAAiB;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,SAAwC;AAC5C,UAAM,KAAK,MAAM,KAAK,MAAA;AACtB,UAAM,KAAK,GAAG,YAAY,YAAY,UAAU;AAChD,UAAM,QAAQ,GAAG,YAAY,UAAU;AACvC,UAAM,QAAQ,MAAM,MAAM,kBAAkB;AAG5C,UAAM,QAAQ,YAAY;AAAA,MACxB,CAAC,KAAK,WAAW,EAAE;AAAA,MACnB,CAAC,KAAK,YAAW,oBAAI,KAAK,MAAgB,GAAE,aAAa;AAAA,IAAA;AAG3D,UAAM,SAAS,MAAM,MAAM,WAAW,OAAO,MAAM;AACnD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AACA,UAAM,WAAW,OAAO;AAExB,QAAI,UAAU;AACZ,aAAQ,SAAiB;AAAA,IAC3B;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAgC;AACrC,UAAM,KAAK,MAAM,KAAK,MAAA;AACtB,UAAM,KAAK,GAAG,YAAY,YAAY,UAAU;AAChD,UAAM,QAAQ,GAAG,YAAY,UAAU;AACvC,UAAM,QAAQ,MAAM,MAAM,kBAAkB;AAE5C,UAAM,QAAQ,YAAY;AAAA,MACxB,CAAC,KAAK,WAAW,EAAE;AAAA,MACnB,CAAC,KAAK,YAAW,oBAAI,KAAK,MAAgB,GAAE,aAAa;AAAA,IAAA;AAG3D,QAAI,SAAS,MAAM,MAAM,WAAW,OAAO,MAAM;AAEjD,WAAO,QAAQ;AACb,YAAM,WAAW,OAAO;AACxB,UAAI,UAAU;AACZ,eAAQ,SAAiB;AAAA,MAC3B;AACA,YAAM;AACN,eAAS,MAAM,OAAO,SAAA;AAAA,IACxB;AAAA,EACF;AACF;;AC7JA,MAAM,UAAU;AAChB,MAAM,uBAAuB;AAC7B,MAAM,wBAAwB;AAMvB,MAAM,gBAAoC;AAAA,EACvC,YAAmD;AAAA,EAEnD,QAAwC;AAC9C,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY,OAAO,SAAS,GAAG;AAAA,QAClC,QAAQ,IAAI,YAAY,YAAY,aAAa;AAE/C,cAAI,CAAC,GAAG,iBAAiB,SAAS,qBAAqB,GAAG;AACxD,kBAAM,QAAQ,GAAG,kBAAkB,uBAAuB;AAAA,cACxD,SAAS;AAAA,YAAA,CACV;AACD,kBAAM,YAAY,oBAAoB,CAAC,aAAa,YAAY,CAAC;AAAA,UACnE;AAEA,cAAI,CAAC,GAAG,iBAAiB,SAAS,oBAAoB,GAAG;AACvD,kBAAM,QAAQ,GAAG,kBAAkB,sBAAsB;AAAA,cACvD,SAAS;AAAA,YAAA,CACV;AACD,kBAAM,YAAY,cAAc,YAAY;AAAA,UAC9C;AAAA,QACF;AAAA,MAAA,CACD;AAAA,IACH;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,SACJ,UACA,MACA,UACA,YACe;AACf,QAAI,aAAa,UAAU;AACzB,YAAM,IAAI,MAAM,8CAA8C,QAAQ,EAAE;AAAA,IAC1E;AACA,UAAM,KAAK,MAAM,KAAK,MAAA;AACtB,UAAM,OAAO,KAAK,aAAa,IAAI;AAEnC,UAAM,GAAG,IAAI,sBAAsB;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,IAAY,CACnC;AAAA,EACH;AAAA,EAEA,MAAM,MAAM,IAA2B;AACrC,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACxD;AAAA,EAEA,cAAc,MAAc,UAA0B;AACpD,WAAO,QAAQ,QAAQ,WAAW,IAAI;AAAA,EACxC;AAAA,EAEQ,aAAa,MAAc,UAAyB;AAC1D,UAAM,iBAAiB,KAAK,IAAI;AAChC,UAAM,cAAc,IAAI,MAAM,eAAe,MAAM;AACnD,aAASC,KAAI,GAAGA,KAAI,eAAe,QAAQA,MAAK;AAC9C,kBAAYA,EAAC,IAAI,eAAe,WAAWA,EAAC;AAAA,IAC9C;AACA,UAAM,YAAY,IAAI,WAAW,WAAW;AAC5C,WAAO,IAAI,KAAK,CAAC,SAAS,GAAG,WAAW,EAAE,MAAM,SAAA,IAAa,MAAS;AAAA,EACxE;AAAA,EAEA,MAAM,MAAM,OAAe,MAAuC;AAChE,UAAM,MAAM,MAAM,OAAO,MAAM,OAAO,IAAI;AAC1C,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,QAAQ,IAAI;AAAA,MACZ,MAAM,MAAM,IAAI,KAAA;AAAA,MAChB,MAAM,MAAM,IAAI,KAAA;AAAA,IAAK;AAAA,EAEzB;AAAA,EAEA,SAAS;AAAA,IACP,YAAY,MAAM,KAAK,OAAO,WAAA;AAAA,IAE9B,MAAM,KAAK,MAAc,QAAiC;AACxD,YAAM,MAAM,IAAI,YAAA;AAChB,YAAM,MAAM,MAAM,OAAO,OAAO,OAAO;AAAA,QACrC;AAAA,QACA,IAAI,OAAO,MAAM;AAAA,QACjB,EAAE,MAAM,QAAQ,MAAM,UAAA;AAAA,QACtB;AAAA,QACA,CAAC,MAAM;AAAA,MAAA;AAET,YAAM,YAAY,MAAM,OAAO,OAAO,OAAO;AAAA,QAC3C;AAAA,QACA;AAAA,QACA,IAAI,OAAO,IAAI;AAAA,MAAA;AAEjB,aAAO,KAAK,uBAAuB,SAAS;AAAA,IAC9C;AAAA,IAEA,MAAM,OACJ,MACA,WACA,QACkB;AAClB,YAAM,WAAW,MAAM,KAAK,KAAK,MAAM,MAAM;AAC7C,aAAO,aAAa;AAAA,IACtB;AAAA;AAAA,IAGA,uBAAuB,QAA6B;AAClD,YAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,UAAI,SAAS;AACb,eAASA,KAAI,GAAGA,KAAI,MAAM,YAAYA,MAAK;AACzC,kBAAU,OAAO,aAAa,MAAMA,EAAC,CAAC;AAAA,MACxC;AACA,aAAO,OACJ,KAAK,MAAM,EACX,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE;AAAA,IACtB;AAAA,EAAA;AAAA,EAGF,WAAW;AAAA,IACT,cAAc,CAAC,SAAyB;AAEtC,YAAM,UAAU,IAAI,YAAA;AACpB,YAAM,QAAQ,QAAQ,OAAO,IAAI;AACjC,UAAI,SAAS;AACb,eAASA,KAAI,GAAGA,KAAI,MAAM,QAAQA,MAAK;AACrC,kBAAU,OAAO,aAAa,MAAMA,EAAC,CAAC;AAAA,MACxC;AACA,aAAO,OACJ,KAAK,MAAM,EACX,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE;AAAA,IACtB;AAAA,IAEA,cAAc,CAAC,SAAyB;AACtC,YAAM,SAAS,KAAK,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAExD,YAAM,SAAS,OAAO,KAAK,MAAM;AACjC,YAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,eAASA,KAAI,GAAGA,KAAI,OAAO,QAAQA,MAAK;AACtC,cAAMA,EAAC,IAAI,OAAO,WAAWA,EAAC;AAAA,MAChC;AACA,YAAM,UAAU,IAAI,YAAA;AACpB,aAAO,QAAQ,OAAO,KAAK;AAAA,IAC7B;AAAA,EAAA;AAAA,EAGF,OAAO,KAAiC;AAEtC,QACE,OAAO,gBAAgB,eACtB,4BACA,yBAAwB,GAAG,GAC5B;AACA,aAAQ,yBAAwB,GAAG;AAAA,IACrC;AAGA,UAAM,YACJ,OAAO,eAAe,cAClB,aACA,OAAO,WAAW,cAChB,SACA,OAAO,SAAS,cACd,OACA,CAAA;AACV,UAAM,YAAY;AAIlB,QAAI;AACF,UAAI,OAAO,YAAY,eAAe,QAAQ,OAAO,QAAQ,IAAI,GAAG,GAAG;AACrE,eAAO,QAAQ,IAAI,GAAG;AAAA,MACxB;AAAA,IACF,SAASC,IAAG;AAAA,IAEZ;AAGA,QAAI,UAAU,gBAAgB,UAAU,aAAa,GAAG,GAAG;AACzD,aAAO,UAAU,aAAa,GAAG;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AACF;AC1MA,MAAM,kBAAkB,IAAI,gBAAA;AAC5B,MAAM,wBAAwC;AAAA,EAC5C,UAAU,CAAC,cAAsB,IAAI,eAAe,SAAS;AAAA,EAC7D,SAAS,MAAM,IAAI,qBAAA;AAAA;AACrB;AASO,SAAS,QAAQ,UAAwB,IAAiB;AAC/D,SAAO,IAAI,gBAAgB,SAAS,uBAAuB,eAAe;AAC5E;AAUO,MAAM,QAAqB,QAAA;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CachedSession } from './storage/types.js';
|
|
2
|
+
export type CacheTier = 'hot' | 'warm' | 'frozen';
|
|
3
|
+
/**
|
|
4
|
+
* Determines the cache tier for a session based on its state and age.
|
|
5
|
+
*
|
|
6
|
+
* Strategy:
|
|
7
|
+
* - **Frozen (Tier 3):** > 30 days old. Immutable.
|
|
8
|
+
* - **Warm (Tier 2):** Terminal state + Verified < 24h ago. High read performance.
|
|
9
|
+
* - **Hot (Tier 1):** Active or Stale. Requires network sync.
|
|
10
|
+
*/
|
|
11
|
+
export declare function determineCacheTier(cached: CachedSession, now?: number): CacheTier;
|
|
12
|
+
/**
|
|
13
|
+
* Helper to check if a cached session is valid to return immediately.
|
|
14
|
+
* Returns true if the session is Frozen or Warm.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isCacheValid(cached: CachedSession | undefined, now?: number): cached is CachedSession;
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { JulesClient, JulesOptions, SessionConfig, SourceManager, AutomatedSession, SessionClient, StorageFactory } from './types.js';
|
|
1
|
+
import { JulesClient, JulesOptions, SessionConfig, SourceManager, AutomatedSession, SessionClient, SessionResource, StorageFactory, JulesQuery, JulesDomain, QueryResult, SyncOptions, SyncStats } from './types.js';
|
|
2
|
+
import { SessionCursor, ListSessionsOptions } from './sessions.js';
|
|
2
3
|
import { Platform } from './platform/types.js';
|
|
4
|
+
import { SessionStorage } from './storage/types.js';
|
|
3
5
|
/**
|
|
4
6
|
* The fully resolved internal configuration for the SDK.
|
|
5
7
|
* @internal
|
|
@@ -18,11 +20,17 @@ export declare class JulesClientImpl implements JulesClient {
|
|
|
18
20
|
* Manages source connections (e.g., GitHub repositories).
|
|
19
21
|
*/
|
|
20
22
|
sources: SourceManager;
|
|
23
|
+
readonly storage: SessionStorage;
|
|
21
24
|
private apiClient;
|
|
22
25
|
private config;
|
|
23
26
|
private options;
|
|
24
27
|
private storageFactory;
|
|
25
28
|
private platform;
|
|
29
|
+
/**
|
|
30
|
+
* Lock to prevent concurrent sync operations.
|
|
31
|
+
* Using a simple boolean for in-process locking.
|
|
32
|
+
*/
|
|
33
|
+
private syncInProgress;
|
|
26
34
|
/**
|
|
27
35
|
* Creates a new instance of the JulesClient.
|
|
28
36
|
*
|
|
@@ -31,6 +39,29 @@ export declare class JulesClientImpl implements JulesClient {
|
|
|
31
39
|
* @param defaultPlatform Platform-specific implementation.
|
|
32
40
|
*/
|
|
33
41
|
constructor(options: JulesOptions | undefined, defaultStorageFactory: StorageFactory, defaultPlatform: Platform);
|
|
42
|
+
/**
|
|
43
|
+
* Fluent API for rich local querying across sessions and activities.
|
|
44
|
+
* This method uses the modular query engine internally.
|
|
45
|
+
*/
|
|
46
|
+
select<T extends JulesDomain>(query: JulesQuery<T>): Promise<QueryResult<T>[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Synchronizes local state with the server.
|
|
49
|
+
* Logic:
|
|
50
|
+
* 1. Find High-Water Mark (newest local record).
|
|
51
|
+
* 2. Stream latest sessions from API.
|
|
52
|
+
* 3. Terminate stream early if 'incremental' and High-Water Mark is hit.
|
|
53
|
+
* 4. Throttled hydration of activities if depth is 'activities'.
|
|
54
|
+
*/
|
|
55
|
+
sync(options?: SyncOptions): Promise<SyncStats>;
|
|
56
|
+
private getCheckpointPath;
|
|
57
|
+
private loadCheckpoint;
|
|
58
|
+
private saveCheckpoint;
|
|
59
|
+
private clearCheckpoint;
|
|
60
|
+
private _getHighWaterMark;
|
|
61
|
+
/**
|
|
62
|
+
* Helper to resolve environment variables with support for frontend prefixes.
|
|
63
|
+
*/
|
|
64
|
+
private getEnv;
|
|
34
65
|
/**
|
|
35
66
|
* Creates a new Jules client instance with updated configuration.
|
|
36
67
|
* This is an immutable operation; the original client instance remains unchanged.
|
|
@@ -39,6 +70,27 @@ export declare class JulesClientImpl implements JulesClient {
|
|
|
39
70
|
* @returns A new JulesClient instance with the updated configuration.
|
|
40
71
|
*/
|
|
41
72
|
with(options: JulesOptions): JulesClient;
|
|
73
|
+
/**
|
|
74
|
+
* Connects to the Jules service with the provided configuration.
|
|
75
|
+
* Acts as a factory method for creating a new client instance.
|
|
76
|
+
*
|
|
77
|
+
* @param options Configuration options for the client.
|
|
78
|
+
* @returns A new JulesClient instance.
|
|
79
|
+
*/
|
|
80
|
+
connect(options: JulesOptions): JulesClient;
|
|
81
|
+
/**
|
|
82
|
+
* Retrieves a session resource using the "Iceberg" caching strategy.
|
|
83
|
+
* * - **Tier 3 (Frozen):** > 30 days old. Returns from cache immediately.
|
|
84
|
+
* - **Tier 2 (Warm):** Terminal state + Verified < 24h ago. Returns from cache.
|
|
85
|
+
* - **Tier 1 (Hot):** Active or Stale. Fetches from network, updates cache, returns.
|
|
86
|
+
*/
|
|
87
|
+
getSessionResource(id: string): Promise<SessionResource>;
|
|
88
|
+
/**
|
|
89
|
+
* Lists sessions with a fluent, pagination-friendly API.
|
|
90
|
+
* @param options Configuration for pagination (pageSize, limit, pageToken)
|
|
91
|
+
* @returns A SessionCursor that can be awaited (first page) or iterated (all pages).
|
|
92
|
+
*/
|
|
93
|
+
sessions(options?: ListSessionsOptions): SessionCursor;
|
|
42
94
|
all<T>(items: T[], mapper: (item: T) => SessionConfig | Promise<SessionConfig>, options?: {
|
|
43
95
|
concurrency?: number;
|
|
44
96
|
stopOnError?: boolean;
|