@oh-my-ghaad/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,187 @@
1
+ import { ZodType, z } from 'zod';
2
+
3
+ interface CollectionNames {
4
+ singular: string;
5
+ plural: string;
6
+ path: string;
7
+ }
8
+ declare class Collection {
9
+ id: string;
10
+ idFunction: () => string;
11
+ names: CollectionNames;
12
+ validator: ZodType;
13
+ constructor({ id, idFunction, names, validator, }: {
14
+ id: string;
15
+ idFunction: () => string;
16
+ names: CollectionNames;
17
+ validator: ZodType;
18
+ });
19
+ }
20
+
21
+ type ValidRepoStatus = "valid" | "pending" | "empty";
22
+ type InvalidRepoStatus = "invalid" | "unknown";
23
+ type RepoStatus = ValidRepoStatus | InvalidRepoStatus;
24
+ type CollectionStatus = "uninitialized" | "valid";
25
+ type CollectionItemStatus = "pending" | "valid" | "invalid";
26
+ type PendingCollectionItemType = "create" | "update" | "delete";
27
+ interface AdapterProps {
28
+ clientId: string;
29
+ redirectUri: string;
30
+ accessManagementUrl: string;
31
+ }
32
+ type Subscription = (collections: Collection[]) => void | Promise<void>;
33
+ interface RepositoryResponse {
34
+ id: string;
35
+ org: string;
36
+ name: string;
37
+ url: string;
38
+ }
39
+ interface PrResponse {
40
+ id: string;
41
+ title: string;
42
+ description: string;
43
+ commitSha?: string;
44
+ createdAt: string;
45
+ }
46
+ type PrRequest = Omit<PrResponse, "id" | "createdAt">;
47
+ interface CommitResponse {
48
+ commitSha: string;
49
+ message: string;
50
+ commitDate: string;
51
+ authorName: string;
52
+ authorImageUrl: string;
53
+ }
54
+ type CommitRequest = Pick<CommitResponse, "message">;
55
+ interface IAdapter extends AdapterProps {
56
+ readonly name: string;
57
+ readonly icon: string;
58
+ readonly primaryColor: string;
59
+ readonly secondaryColor: string;
60
+ readonly oauthUrl: string;
61
+ readonly baseUrl: string;
62
+ fetchRepositories(): Promise<RepositoryResponse[]>;
63
+ fetchFile(filePath: string): Promise<string>;
64
+ fetchFileHistory(filePath: string): Promise<CommitResponse[]>;
65
+ fetchDirectory(directoryPath: string): Promise<string[]>;
66
+ createCommit(commitRequest: CommitRequest): Promise<void>;
67
+ createFile(filePath: string, content: string, message?: string): Promise<void>;
68
+ updateFile(filePath: string, content: string, message?: string): Promise<void>;
69
+ deleteFile(filePath: string, message?: string): Promise<void>;
70
+ fetchPullRequests(): Promise<PrResponse[]>;
71
+ createPullRequest(prRequest: PrRequest): Promise<void>;
72
+ fetchPullRequest(): Promise<PrResponse>;
73
+ updatePullRequest(prRequest: PrRequest): Promise<void>;
74
+ deletePullRequest(id: string): Promise<void>;
75
+ }
76
+ interface BaseCollectionItem {
77
+ id: string;
78
+ fileName: string;
79
+ }
80
+
81
+ declare class Adapter implements AdapterProps {
82
+ clientId: string;
83
+ redirectUri: string;
84
+ token: string | null;
85
+ owner: string | null;
86
+ repo: string | null;
87
+ accessManagementUrl: string;
88
+ protected unauthorizedHandler: (() => void | Promise<void>) | null;
89
+ constructor(props: AdapterProps);
90
+ setOwner(owner: string | null): void;
91
+ setRepo(repo: string | null): void;
92
+ setToken(token: string | null): void;
93
+ setUnauthorizedHandler(handler: () => void | Promise<void>): void;
94
+ }
95
+
96
+ declare const appConfigSchema: z.ZodObject<{
97
+ appName: z.ZodString;
98
+ appId: z.ZodString;
99
+ persisted: z.ZodDefault<z.ZodBoolean>;
100
+ persistedTokenKey: z.ZodDefault<z.ZodString>;
101
+ persistedRepoKey: z.ZodDefault<z.ZodString>;
102
+ persistedOwnerKey: z.ZodDefault<z.ZodString>;
103
+ persistedAdapterKey: z.ZodDefault<z.ZodString>;
104
+ }, "strip", z.ZodTypeAny, {
105
+ appName?: string;
106
+ appId?: string;
107
+ persisted?: boolean;
108
+ persistedTokenKey?: string;
109
+ persistedRepoKey?: string;
110
+ persistedOwnerKey?: string;
111
+ persistedAdapterKey?: string;
112
+ }, {
113
+ appName?: string;
114
+ appId?: string;
115
+ persisted?: boolean;
116
+ persistedTokenKey?: string;
117
+ persistedRepoKey?: string;
118
+ persistedOwnerKey?: string;
119
+ persistedAdapterKey?: string;
120
+ }>;
121
+ type AppConfig = z.infer<typeof appConfigSchema>;
122
+ declare const repoConfigSchema: z.ZodObject<{
123
+ prBasedMutations: z.ZodDefault<z.ZodBoolean>;
124
+ }, "strip", z.ZodTypeAny, {
125
+ prBasedMutations?: boolean;
126
+ }, {
127
+ prBasedMutations?: boolean;
128
+ }>;
129
+ type RepoConfig = z.infer<typeof repoConfigSchema> & {
130
+ status: RepoStatus;
131
+ };
132
+
133
+ declare class Engine {
134
+ private status;
135
+ private subscriptions;
136
+ private adapters;
137
+ private currentAdapter;
138
+ private collections;
139
+ private appConfig;
140
+ private repoConfig;
141
+ private collectionItems;
142
+ constructor({ appConfig, adapters, collections, }: {
143
+ adapters: (Adapter & IAdapter)[];
144
+ collections: Collection[];
145
+ appConfig: AppConfig;
146
+ });
147
+ setUnauthorizedHandler(handler: () => void | Promise<void>): void;
148
+ subscribe(subscription: Subscription): void;
149
+ unsubscribe(subscription: Subscription): void;
150
+ private notifySubscribers;
151
+ setRepoOwner(owner: string | null): void;
152
+ setRepoName(name: string | null): void;
153
+ getRepoStatus(): RepoStatus;
154
+ getAppConfig(): {
155
+ appName?: string;
156
+ appId?: string;
157
+ persisted?: boolean;
158
+ persistedTokenKey?: string;
159
+ persistedRepoKey?: string;
160
+ persistedOwnerKey?: string;
161
+ persistedAdapterKey?: string;
162
+ };
163
+ getRepoConfig(): RepoConfig;
164
+ fetchRepoConfig(): Promise<RepoConfig>;
165
+ sync(): Promise<void>;
166
+ getToken(): string;
167
+ setToken(token: string | null): void;
168
+ getAdapters(): (Adapter & IAdapter)[];
169
+ setAdapter(adapter: (Adapter & IAdapter) | null): this;
170
+ getAdapter(): Adapter & IAdapter;
171
+ getCollections(): Collection[];
172
+ getCollection<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"]): Collection | undefined;
173
+ getCollectionItems<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"]): z.infer<T["validator"]>[];
174
+ fetchCollectionItems<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"], force?: boolean): Promise<z.infer<T["validator"]>[]>;
175
+ fetchCollectionItem<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"], itemId: z.infer<T["validator"]>["id"]): Promise<z.infer<T["validator"]> | null>;
176
+ addToCollection<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"], data: z.infer<T["validator"]>): Promise<z.infer<T["validator"]>[]>;
177
+ removeFromCollection<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"], itemId: z.infer<T["validator"]>["id"]): Promise<z.infer<T["validator"]>[]>;
178
+ updateInCollection<T extends Collection>(collectionLookupValue: T["id"] | T["names"]["singular"] | T["names"]["plural"], itemId: string, data: z.infer<T["validator"]>): Promise<z.infer<T["validator"]>[]>;
179
+ initializeCollection(collection: Collection): Promise<void>;
180
+ initializeRepoConfig(repoConfig: RepoConfig): Promise<void>;
181
+ initialize(): Promise<void>;
182
+ private lastFetchPullRequestTimestamp;
183
+ private cachedPullRequests;
184
+ fetchPullRequests(force?: boolean): Promise<PrResponse[]>;
185
+ }
186
+
187
+ export { Adapter, type AdapterProps, type AppConfig, type BaseCollectionItem, Collection, type CollectionItemStatus, type CollectionStatus, type CommitRequest, type CommitResponse, Engine, type IAdapter, type InvalidRepoStatus, type PendingCollectionItemType, type PrRequest, type PrResponse, type RepoConfig, type RepoStatus, type RepositoryResponse, type Subscription, type ValidRepoStatus, appConfigSchema, repoConfigSchema };
package/dist/index.js ADDED
@@ -0,0 +1,430 @@
1
+ // src/validators.ts
2
+ import { z } from "zod";
3
+ var appConfigSchema = z.object({
4
+ appName: z.string(),
5
+ appId: z.string(),
6
+ persisted: z.boolean().default(true),
7
+ persistedTokenKey: z.string().default("token"),
8
+ persistedRepoKey: z.string().default("repo"),
9
+ persistedOwnerKey: z.string().default("owner"),
10
+ persistedAdapterKey: z.string().default("adapter")
11
+ });
12
+ var repoConfigSchema = z.object({
13
+ prBasedMutations: z.boolean().default(true)
14
+ });
15
+
16
+ // src/engine.ts
17
+ var storage = typeof window !== "undefined" ? window.localStorage : null;
18
+ var Engine = class {
19
+ status = "unknown";
20
+ subscriptions = /* @__PURE__ */ new Set();
21
+ adapters = [];
22
+ currentAdapter = null;
23
+ collections = [];
24
+ appConfig;
25
+ repoConfig;
26
+ collectionItems = {};
27
+ constructor({
28
+ appConfig,
29
+ adapters,
30
+ collections
31
+ }) {
32
+ this.appConfig = appConfig;
33
+ this.adapters = adapters;
34
+ this.collections = collections;
35
+ if (this.adapters.length === 1) {
36
+ this.setAdapter(this.adapters[0]);
37
+ }
38
+ if (this.appConfig.persisted) {
39
+ const persistedAdapter = storage?.getItem(
40
+ this.appConfig.persistedAdapterKey || "adapter"
41
+ );
42
+ if (persistedAdapter) {
43
+ const adapter = this.adapters.find(
44
+ (adapter2) => adapter2.name === persistedAdapter
45
+ );
46
+ if (adapter) {
47
+ this.setAdapter(adapter);
48
+ }
49
+ }
50
+ const persistedToken = storage?.getItem(
51
+ this.appConfig.persistedTokenKey || "token"
52
+ );
53
+ if (persistedToken) {
54
+ this.setToken(persistedToken);
55
+ }
56
+ const persistedRepo = storage?.getItem(
57
+ this.appConfig.persistedRepoKey || "repo"
58
+ );
59
+ if (persistedRepo) {
60
+ this.getAdapter()?.setRepo(persistedRepo);
61
+ }
62
+ const persistedOwner = storage?.getItem(
63
+ this.appConfig.persistedOwnerKey || "owner"
64
+ );
65
+ if (persistedOwner) {
66
+ this.getAdapter()?.setOwner(persistedOwner);
67
+ }
68
+ }
69
+ }
70
+ setUnauthorizedHandler(handler) {
71
+ this.adapters.forEach((adapter) => {
72
+ adapter.setUnauthorizedHandler(handler);
73
+ });
74
+ }
75
+ subscribe(subscription) {
76
+ this.subscriptions.add(subscription);
77
+ }
78
+ unsubscribe(subscription) {
79
+ this.subscriptions.delete(subscription);
80
+ }
81
+ notifySubscribers() {
82
+ this.subscriptions.forEach(
83
+ (subscription) => subscription(this.collections)
84
+ );
85
+ }
86
+ setRepoOwner(owner) {
87
+ if (this.appConfig.persisted) {
88
+ storage?.setItem(
89
+ this.appConfig.persistedOwnerKey || "owner",
90
+ owner || ""
91
+ );
92
+ }
93
+ this.adapters.forEach((adapter) => {
94
+ adapter.setOwner(owner);
95
+ });
96
+ this.notifySubscribers();
97
+ }
98
+ setRepoName(name) {
99
+ if (this.appConfig.persisted) {
100
+ storage?.setItem(this.appConfig.persistedRepoKey || "repo", name || "");
101
+ }
102
+ this.adapters.forEach((adapter) => {
103
+ adapter.setRepo(name);
104
+ });
105
+ this.notifySubscribers();
106
+ }
107
+ getRepoStatus() {
108
+ return this.status;
109
+ }
110
+ getAppConfig() {
111
+ return this.appConfig;
112
+ }
113
+ getRepoConfig() {
114
+ return this.repoConfig;
115
+ }
116
+ async fetchRepoConfig() {
117
+ const rawConfigString = await this.currentAdapter?.fetchFile("config.json").catch(() => {
118
+ console.log(
119
+ "OH My GHaaD: Could not fetch the config file, setting status to empty"
120
+ );
121
+ });
122
+ if (!rawConfigString) {
123
+ this.status = "empty";
124
+ throw new Error("No config file found");
125
+ }
126
+ const rawConfig = JSON.parse(rawConfigString);
127
+ const parsedConfig = repoConfigSchema.safeParse(rawConfig);
128
+ let partialConfig = parsedConfig.data;
129
+ if (parsedConfig.success) {
130
+ this.status = "valid";
131
+ } else {
132
+ this.status = "invalid";
133
+ }
134
+ this.repoConfig = partialConfig;
135
+ return partialConfig;
136
+ }
137
+ async sync() {
138
+ const [repoConfig, ...fetchedCollectionItems] = await Promise.all([
139
+ this.fetchRepoConfig().catch((error) => {
140
+ return {
141
+ prBasedMutations: false
142
+ };
143
+ }),
144
+ ...this.collections.map(async (collection) => ({
145
+ collectionId: collection.id,
146
+ items: await this.fetchCollectionItems(collection.id).catch((error) => {
147
+ return [];
148
+ })
149
+ }))
150
+ ]);
151
+ this.notifySubscribers();
152
+ }
153
+ getToken() {
154
+ const currentAdapter = this.getAdapter();
155
+ if (currentAdapter) {
156
+ return currentAdapter.token;
157
+ }
158
+ }
159
+ setToken(token) {
160
+ if (this.appConfig.persisted) {
161
+ storage?.setItem(
162
+ this.appConfig.persistedTokenKey || "token",
163
+ token || ""
164
+ );
165
+ }
166
+ this.adapters.forEach((adapter) => {
167
+ adapter.setToken(token);
168
+ });
169
+ this.notifySubscribers();
170
+ }
171
+ getAdapters() {
172
+ return this.adapters;
173
+ }
174
+ setAdapter(adapter) {
175
+ if (this.appConfig.persisted) {
176
+ storage?.setItem(
177
+ this.appConfig.persistedAdapterKey || "adapter",
178
+ adapter?.name || ""
179
+ );
180
+ }
181
+ this.currentAdapter = adapter;
182
+ this.notifySubscribers();
183
+ return this;
184
+ }
185
+ getAdapter() {
186
+ return this.currentAdapter;
187
+ }
188
+ getCollections() {
189
+ return this.collections;
190
+ }
191
+ getCollection(collectionLookupValue) {
192
+ return this.collections.find(
193
+ (c) => c.id === collectionLookupValue || Object.values(c.names).includes(collectionLookupValue)
194
+ );
195
+ }
196
+ getCollectionItems(collectionLookupValue) {
197
+ const collection = this.getCollection(collectionLookupValue);
198
+ if (!collection) {
199
+ throw new Error("Collection not found");
200
+ }
201
+ if (!this.collectionItems[collection.id]) {
202
+ return [];
203
+ }
204
+ return this.collectionItems[collection.id];
205
+ }
206
+ async fetchCollectionItems(collectionLookupValue, force = false) {
207
+ if (!this.currentAdapter) {
208
+ throw new Error("No adapter selected");
209
+ }
210
+ const collection = this.getCollection(collectionLookupValue);
211
+ if (!collection) {
212
+ throw new Error("Collection not found");
213
+ }
214
+ const rawCollectionItems = await this.currentAdapter.fetchDirectory(
215
+ `collections/${collection.names.path}`
216
+ );
217
+ const collectionItems = rawCollectionItems?.map((item) => {
218
+ return collection.validator.parse(JSON.parse(item));
219
+ }) || [];
220
+ this.collectionItems[collection.id] = collectionItems;
221
+ this.notifySubscribers();
222
+ return collectionItems;
223
+ }
224
+ async fetchCollectionItem(collectionLookupValue, itemId) {
225
+ const collection = this.getCollection(collectionLookupValue);
226
+ if (!collection) {
227
+ throw new Error("Collection not found");
228
+ }
229
+ const rawCollectionItem = await this.currentAdapter.fetchFile(
230
+ `collections/${collection.names.path}/${itemId}.json`
231
+ );
232
+ if (!rawCollectionItem) {
233
+ return null;
234
+ }
235
+ const collectionItem = collection.validator.parse(
236
+ JSON.parse(rawCollectionItem)
237
+ );
238
+ return collectionItem;
239
+ }
240
+ async addToCollection(collectionLookupValue, data) {
241
+ if (!this.currentAdapter) {
242
+ throw new Error("No adapter selected");
243
+ }
244
+ const collection = this.getCollection(collectionLookupValue);
245
+ if (!collection) {
246
+ throw new Error("Collection not found");
247
+ }
248
+ const rawNewItem = {
249
+ ...data,
250
+ id: collection.idFunction()
251
+ };
252
+ const item = collection.validator.parse(rawNewItem);
253
+ let request;
254
+ request = this.currentAdapter.createFile(
255
+ `collections/${collection.names.path}/${item.id}.json`,
256
+ JSON.stringify(item, null, 2),
257
+ `Add ${collection.names.singular} ${item.id}`
258
+ );
259
+ return request.then(() => {
260
+ this.collectionItems[collection.id] = [
261
+ ...this.collectionItems[collection.id] || [],
262
+ item
263
+ ];
264
+ return this.collectionItems[collection.id];
265
+ });
266
+ }
267
+ async removeFromCollection(collectionLookupValue, itemId) {
268
+ if (!this.currentAdapter) {
269
+ throw new Error("No adapter selected");
270
+ }
271
+ const collection = this.getCollection(collectionLookupValue);
272
+ if (!collection) {
273
+ throw new Error("Collection not found");
274
+ }
275
+ let request;
276
+ request = this.currentAdapter.deleteFile(
277
+ `collections/${collection.names.path}/${itemId}.json`,
278
+ `Remove ${collection.names.singular} ${itemId}`
279
+ );
280
+ await request.then(() => {
281
+ this.collectionItems[collection.id] = this.collectionItems[collection.id]?.filter(
282
+ (item) => item.id !== itemId
283
+ ) || [];
284
+ return this.collectionItems[collection.id];
285
+ });
286
+ this.notifySubscribers();
287
+ return this.collectionItems[collection.id];
288
+ }
289
+ async updateInCollection(collectionLookupValue, itemId, data) {
290
+ if (!this.currentAdapter) {
291
+ throw new Error("No adapter selected");
292
+ }
293
+ const collection = this.getCollection(collectionLookupValue);
294
+ if (!collection) {
295
+ throw new Error("Collection not found");
296
+ }
297
+ const existingItem = this.collectionItems[collection.id].find(
298
+ (item2) => item2.id === itemId
299
+ );
300
+ if (!existingItem) {
301
+ throw new Error("Item not found");
302
+ }
303
+ const item = collection.validator.parse(data);
304
+ await this.currentAdapter.updateFile(
305
+ `collections/${collection.names.path}/${itemId}.json`,
306
+ JSON.stringify(
307
+ {
308
+ ...item,
309
+ id: itemId
310
+ },
311
+ null,
312
+ 2
313
+ ),
314
+ `Update ${collection.names.singular} ${itemId}`
315
+ );
316
+ this.collectionItems[collection.id] = this.collectionItems[collection.id].map((_item) => {
317
+ if (_item.id === itemId) {
318
+ return item;
319
+ }
320
+ return _item;
321
+ });
322
+ this.notifySubscribers();
323
+ return this.collectionItems[collection.id];
324
+ }
325
+ async initializeCollection(collection) {
326
+ const adapter = this.getAdapter();
327
+ if (!adapter) {
328
+ throw new Error("No adapter selected");
329
+ }
330
+ return adapter.createFile(
331
+ `collections/${collection.names.path}/.gitkeep`,
332
+ "",
333
+ `Create collection: ${collection.names.singular}`
334
+ );
335
+ }
336
+ async initializeRepoConfig(repoConfig) {
337
+ const adapter = this.getAdapter();
338
+ if (!adapter) {
339
+ throw new Error("No adapter selected");
340
+ }
341
+ return adapter.createFile(
342
+ "config.json",
343
+ JSON.stringify(
344
+ repoConfig ?? {
345
+ prBasedMutations: false
346
+ }
347
+ )
348
+ );
349
+ }
350
+ async initialize() {
351
+ const repoConfig = this.getRepoConfig();
352
+ await this.initializeRepoConfig(repoConfig);
353
+ for (const collection of this.collections) {
354
+ await this.initializeCollection(collection);
355
+ }
356
+ this.status = "valid";
357
+ this.notifySubscribers();
358
+ }
359
+ // Grouping together props and methods for caching PRs
360
+ lastFetchPullRequestTimestamp = 0;
361
+ cachedPullRequests = [];
362
+ async fetchPullRequests(force = false) {
363
+ const adapter = this.getAdapter();
364
+ if (!adapter) {
365
+ throw new Error("No adapter selected");
366
+ }
367
+ if (force) {
368
+ this.lastFetchPullRequestTimestamp = 0;
369
+ }
370
+ if (this.lastFetchPullRequestTimestamp > Date.now() - 1e3 * 60 * 5) {
371
+ return this.cachedPullRequests;
372
+ } else {
373
+ return adapter.fetchPullRequests();
374
+ }
375
+ }
376
+ };
377
+
378
+ // src/collection.ts
379
+ var Collection = class {
380
+ id;
381
+ idFunction;
382
+ names;
383
+ validator;
384
+ constructor({
385
+ id,
386
+ idFunction,
387
+ names,
388
+ validator
389
+ }) {
390
+ this.id = id;
391
+ this.idFunction = idFunction;
392
+ this.names = names;
393
+ this.validator = validator;
394
+ }
395
+ };
396
+
397
+ // src/adapter.ts
398
+ var Adapter = class {
399
+ clientId;
400
+ redirectUri;
401
+ token;
402
+ owner;
403
+ repo;
404
+ accessManagementUrl;
405
+ unauthorizedHandler = null;
406
+ constructor(props) {
407
+ this.clientId = props.clientId;
408
+ this.redirectUri = props.redirectUri;
409
+ this.accessManagementUrl = props.accessManagementUrl;
410
+ }
411
+ setOwner(owner) {
412
+ this.owner = owner;
413
+ }
414
+ setRepo(repo) {
415
+ this.repo = repo;
416
+ }
417
+ setToken(token) {
418
+ this.token = token;
419
+ }
420
+ setUnauthorizedHandler(handler) {
421
+ this.unauthorizedHandler = handler;
422
+ }
423
+ };
424
+ export {
425
+ Adapter,
426
+ Collection,
427
+ Engine,
428
+ appConfigSchema,
429
+ repoConfigSchema
430
+ };
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@oh-my-ghaad/core",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "types": "dist/index.d.ts",
8
+ "keywords": [],
9
+ "author": "",
10
+ "license": "MIT",
11
+ "devDependencies": {
12
+ "tsup": "^8.5.0",
13
+ "typescript": "5.8.2"
14
+ },
15
+ "dependencies": {
16
+ "zod": "^3.24.4"
17
+ },
18
+ "scripts": {
19
+ "dev": "tsup src/index.ts --watch --dts --format esm,cjs",
20
+ "build": "tsup src/index.ts --dts --format esm,cjs",
21
+ "test": "echo \"Error: no test specified\" && exit 1"
22
+ }
23
+ }
package/src/adapter.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { AdapterProps } from "./types";
2
+
3
+ export class Adapter implements AdapterProps {
4
+ clientId: string;
5
+ redirectUri: string;
6
+ token: string | null;
7
+ owner: string | null;
8
+ repo: string | null;
9
+ accessManagementUrl: string;
10
+ protected unauthorizedHandler: (() => void | Promise<void>) | null = null;
11
+
12
+ constructor(props: AdapterProps) {
13
+ this.clientId = props.clientId;
14
+ this.redirectUri = props.redirectUri;
15
+ this.accessManagementUrl = props.accessManagementUrl;
16
+ }
17
+
18
+ setOwner(owner: string | null) {
19
+ this.owner = owner;
20
+ }
21
+
22
+ setRepo(repo: string | null) {
23
+ this.repo = repo;
24
+ }
25
+
26
+ setToken(token: string | null) {
27
+ this.token = token;
28
+ }
29
+
30
+ setUnauthorizedHandler(handler: () => void | Promise<void>) {
31
+ this.unauthorizedHandler = handler;
32
+ }
33
+ }
@@ -0,0 +1,31 @@
1
+ import type { ZodType } from "zod";
2
+
3
+ interface CollectionNames {
4
+ singular: string;
5
+ plural: string;
6
+ path: string;
7
+ }
8
+
9
+ export class Collection {
10
+ id: string;
11
+ idFunction: () => string;
12
+ names: CollectionNames;
13
+ validator: ZodType;
14
+
15
+ constructor({
16
+ id,
17
+ idFunction,
18
+ names,
19
+ validator,
20
+ }: {
21
+ id: string;
22
+ idFunction: () => string;
23
+ names: CollectionNames;
24
+ validator: ZodType;
25
+ }) {
26
+ this.id = id;
27
+ this.idFunction = idFunction;
28
+ this.names = names;
29
+ this.validator = validator;
30
+ }
31
+ }