@slates/profiles 1.0.0-rc.3 → 1.0.0-rc.5
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/dist/index.cjs +37 -23
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.module.js +37 -23
- package/package.json +4 -4
- package/src/client.ts +26 -12
- package/src/store.test.ts +213 -1
- package/src/store.ts +27 -12
package/dist/index.cjs
CHANGED
|
@@ -82,11 +82,13 @@ var resolveSlatesCliRoot = (cwd = process.cwd()) => {
|
|
|
82
82
|
return cwd;
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
|
-
var
|
|
86
|
-
var
|
|
85
|
+
var resolveSlatesCliDirFromRoot = (rootDir) => import_path.default.join(rootDir, CLI_DIR_NAME);
|
|
86
|
+
var resolveSlatesCliProfilesDirFromRoot = (rootDir) => import_path.default.join(resolveSlatesCliDirFromRoot(rootDir), PROFILES_DIR_NAME);
|
|
87
|
+
var resolveSlatesCliDir = (cwd = process.cwd()) => resolveSlatesCliDirFromRoot(resolveSlatesCliRoot(cwd));
|
|
88
|
+
var resolveSlatesCliProfilesDir = (cwd = process.cwd()) => resolveSlatesCliProfilesDirFromRoot(resolveSlatesCliRoot(cwd));
|
|
87
89
|
var normalizeScopeKey = (scopeKey) => import_path.default.posix.normalize(scopeKey.replace(/\\/g, "/")).replace(/^\.?\//, "");
|
|
88
90
|
var splitScopeKey = (scopeKey) => normalizeScopeKey(scopeKey).split("/").filter(Boolean).filter((segment) => segment !== "." && segment !== "..");
|
|
89
|
-
var resolveScopedStoreDir = (rootDir, scopeKey) => import_path.default.join(
|
|
91
|
+
var resolveScopedStoreDir = (rootDir, scopeKey) => import_path.default.join(resolveSlatesCliProfilesDirFromRoot(rootDir), ...splitScopeKey(scopeKey));
|
|
90
92
|
var resolveScopedStorePath = (rootDir, scopeKey) => import_path.default.join(resolveScopedStoreDir(rootDir, scopeKey), STORE_FILE_NAME);
|
|
91
93
|
var inferRootDirFromStorePath = (storePath) => {
|
|
92
94
|
let normalized = import_path.default.resolve(storePath);
|
|
@@ -99,7 +101,7 @@ var inferRootDirFromStorePath = (storePath) => {
|
|
|
99
101
|
return import_path.default.join(import_path.default.sep, ...rootParts);
|
|
100
102
|
};
|
|
101
103
|
var resolveScopeKeyFromStorePath = (rootDir, storePath) => {
|
|
102
|
-
let profilesDir =
|
|
104
|
+
let profilesDir = resolveSlatesCliProfilesDirFromRoot(rootDir);
|
|
103
105
|
let relativeDir = import_path.default.relative(profilesDir, import_path.default.dirname(storePath));
|
|
104
106
|
if (!relativeDir || relativeDir.startsWith("..") || import_path.default.isAbsolute(relativeDir)) {
|
|
105
107
|
return null;
|
|
@@ -130,7 +132,7 @@ var isProfileInScope = (rootDir, scopeKey, profile) => {
|
|
|
130
132
|
return relative !== "" && !relative.startsWith("..") && !import_path.default.isAbsolute(relative);
|
|
131
133
|
};
|
|
132
134
|
var loadMigratedLegacyStore = async (rootDir, scopeKey) => {
|
|
133
|
-
let legacyStorePath = import_path.default.join(
|
|
135
|
+
let legacyStorePath = import_path.default.join(resolveSlatesCliDirFromRoot(rootDir), STORE_FILE_NAME);
|
|
134
136
|
let legacy = await readStoreData(legacyStorePath);
|
|
135
137
|
if (!legacy) {
|
|
136
138
|
return createEmptyStore();
|
|
@@ -149,22 +151,25 @@ var loadMigratedLegacyStore = async (rootDir, scopeKey) => {
|
|
|
149
151
|
};
|
|
150
152
|
};
|
|
151
153
|
var SlatesCliStore = class _SlatesCliStore {
|
|
152
|
-
constructor(rootDir, dirPath, storePath, scope, data) {
|
|
154
|
+
constructor(rootDir, cliDir, dirPath, storePath, scope, data) {
|
|
153
155
|
this.rootDir = rootDir;
|
|
156
|
+
this.cliDir = cliDir;
|
|
154
157
|
this.dirPath = dirPath;
|
|
155
158
|
this.storePath = storePath;
|
|
156
159
|
this.scope = scope;
|
|
157
160
|
this.data = data;
|
|
158
161
|
}
|
|
159
162
|
rootDir;
|
|
163
|
+
cliDir;
|
|
160
164
|
dirPath;
|
|
161
165
|
storePath;
|
|
162
166
|
scope;
|
|
163
167
|
data;
|
|
164
168
|
static async open(opts = {}) {
|
|
165
|
-
let
|
|
166
|
-
let
|
|
167
|
-
let
|
|
169
|
+
let storageRootDir = opts.storePath ? inferRootDirFromStorePath(opts.storePath) : resolveSlatesCliRoot(opts.cwd);
|
|
170
|
+
let rootDir = opts.rootDir ?? storageRootDir;
|
|
171
|
+
let cliDir = resolveSlatesCliDirFromRoot(storageRootDir);
|
|
172
|
+
let scopeKey = opts.storePath ? resolveScopeKeyFromStorePath(storageRootDir, opts.storePath) : opts.scope?.key ? normalizeScopeKey(opts.scope.key) : null;
|
|
168
173
|
let dirPath = opts.storePath ? import_path.default.dirname(opts.storePath) : scopeKey ? resolveScopedStoreDir(rootDir, scopeKey) : cliDir;
|
|
169
174
|
let storePath = opts.storePath ?? (scopeKey ? resolveScopedStorePath(rootDir, scopeKey) : import_path.default.join(cliDir, STORE_FILE_NAME));
|
|
170
175
|
await ensureDir(cliDir);
|
|
@@ -176,12 +181,13 @@ var SlatesCliStore = class _SlatesCliStore {
|
|
|
176
181
|
currentProfileId: parsed.currentProfileId ?? null,
|
|
177
182
|
profiles: parsed.profiles ?? {},
|
|
178
183
|
oauthCredentials: parsed.oauthCredentials ?? {}
|
|
179
|
-
} : scopeKey ? await loadMigratedLegacyStore(rootDir, scopeKey) : createEmptyStore();
|
|
184
|
+
} : opts.storePath ? createEmptyStore() : scopeKey ? await loadMigratedLegacyStore(rootDir, scopeKey) : createEmptyStore();
|
|
180
185
|
if (!parsed) {
|
|
181
186
|
await (0, import_promises.writeFile)(storePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
182
187
|
}
|
|
183
188
|
return new _SlatesCliStore(
|
|
184
189
|
rootDir,
|
|
190
|
+
cliDir,
|
|
185
191
|
dirPath,
|
|
186
192
|
storePath,
|
|
187
193
|
scopeKey ? { key: scopeKey, name: opts.scope?.name } : null,
|
|
@@ -190,8 +196,8 @@ var SlatesCliStore = class _SlatesCliStore {
|
|
|
190
196
|
}
|
|
191
197
|
async save() {
|
|
192
198
|
await ensureDir(this.dirPath);
|
|
193
|
-
await ensureDir(
|
|
194
|
-
await ensureGitIgnore(
|
|
199
|
+
await ensureDir(this.cliDir);
|
|
200
|
+
await ensureGitIgnore(this.cliDir);
|
|
195
201
|
await (0, import_promises.writeFile)(this.storePath, JSON.stringify(this.data, null, 2) + "\n", "utf-8");
|
|
196
202
|
}
|
|
197
203
|
listProfiles() {
|
|
@@ -336,15 +342,18 @@ var SlatesCliStore = class _SlatesCliStore {
|
|
|
336
342
|
var openSlatesCliStore = async (opts = {}) => SlatesCliStore.open(opts);
|
|
337
343
|
|
|
338
344
|
// src/client.ts
|
|
339
|
-
var resolveEntryPath = (entry,
|
|
345
|
+
var resolveEntryPath = (entry, opts = {}) => {
|
|
340
346
|
if (import_path2.default.isAbsolute(entry)) return entry;
|
|
341
|
-
return import_path2.default.resolve(resolveSlatesCliRoot(cwd), entry);
|
|
347
|
+
return import_path2.default.resolve(opts.rootDir ?? resolveSlatesCliRoot(opts.cwd), entry);
|
|
342
348
|
};
|
|
343
|
-
var loadSlateFromProfile = async (profile,
|
|
349
|
+
var loadSlateFromProfile = async (profile, opts = {}) => {
|
|
344
350
|
if (profile.target.type !== "local") {
|
|
345
351
|
throw new Error(`Unsupported profile target type: ${profile.target.type}`);
|
|
346
352
|
}
|
|
347
|
-
let modulePath = resolveEntryPath(profile.target.entry,
|
|
353
|
+
let modulePath = resolveEntryPath(profile.target.entry, {
|
|
354
|
+
cwd: opts.cwd,
|
|
355
|
+
rootDir: opts.store?.rootDir
|
|
356
|
+
});
|
|
348
357
|
let loaded = await import((0, import_url.pathToFileURL)(modulePath).href);
|
|
349
358
|
let exportName = profile.target.exportName;
|
|
350
359
|
let slate = (exportName ? loaded[exportName] : void 0) ?? loaded.provider ?? loaded.slate ?? loaded.default;
|
|
@@ -357,7 +366,7 @@ var loadSlateFromProfile = async (profile, cwd) => {
|
|
|
357
366
|
};
|
|
358
367
|
var createSlatesClientFromProfile = async (profile, opts = {}) => {
|
|
359
368
|
let firstAuth = Object.values(profile.auth)[0];
|
|
360
|
-
let slate = await loadSlateFromProfile(profile, opts
|
|
369
|
+
let slate = await loadSlateFromProfile(profile, opts);
|
|
361
370
|
let client = (0, import_client.createSlatesClient)({
|
|
362
371
|
transport: (0, import_client.createLocalSlateTransport)({ slate }),
|
|
363
372
|
state: {
|
|
@@ -369,20 +378,25 @@ var createSlatesClientFromProfile = async (profile, opts = {}) => {
|
|
|
369
378
|
} : null
|
|
370
379
|
}
|
|
371
380
|
});
|
|
372
|
-
if (firstAuth) {
|
|
381
|
+
if (firstAuth && opts.autoRefresh !== false) {
|
|
373
382
|
attachAutoRefresh(client, profile, firstAuth, opts.store);
|
|
374
383
|
}
|
|
375
384
|
return client;
|
|
376
385
|
};
|
|
377
386
|
var EXPIRY_BUFFER_MS = 60 * 1e3;
|
|
378
|
-
var
|
|
379
|
-
if (auth.authType !== "auth.oauth") return false;
|
|
380
|
-
if (!auth.clientId || !auth.clientSecret) return false;
|
|
381
|
-
if (typeof auth.output?.refreshToken !== "string" || !auth.output.refreshToken) return false;
|
|
387
|
+
var hasExpiredOrExpiringOutput = (auth) => {
|
|
382
388
|
if (typeof auth.output?.expiresAt !== "string" || !auth.output.expiresAt) return false;
|
|
383
389
|
let expiresAt = Date.parse(auth.output.expiresAt);
|
|
384
390
|
return Number.isFinite(expiresAt) && expiresAt <= Date.now() + EXPIRY_BUFFER_MS;
|
|
385
391
|
};
|
|
392
|
+
var shouldRefreshAuth = (auth) => {
|
|
393
|
+
if (!hasExpiredOrExpiringOutput(auth)) return false;
|
|
394
|
+
if (auth.authType === "auth.oauth") {
|
|
395
|
+
if (!auth.clientId || !auth.clientSecret) return false;
|
|
396
|
+
if (typeof auth.output?.refreshToken !== "string" || !auth.output.refreshToken) return false;
|
|
397
|
+
}
|
|
398
|
+
return true;
|
|
399
|
+
};
|
|
386
400
|
var attachAutoRefresh = (client, profile, storedAuth, store) => {
|
|
387
401
|
let baseRequest = client.request.bind(client);
|
|
388
402
|
let inflightRefresh = null;
|
|
@@ -391,7 +405,7 @@ var attachAutoRefresh = (client, profile, storedAuth, store) => {
|
|
|
391
405
|
await inflightRefresh;
|
|
392
406
|
return;
|
|
393
407
|
}
|
|
394
|
-
if (!
|
|
408
|
+
if (!shouldRefreshAuth(storedAuth)) {
|
|
395
409
|
return;
|
|
396
410
|
}
|
|
397
411
|
inflightRefresh = (async () => {
|
package/dist/index.d.cts
CHANGED
|
@@ -66,13 +66,15 @@ declare let resolveSlatesCliDir: (cwd?: string) => string;
|
|
|
66
66
|
declare let resolveSlatesCliProfilesDir: (cwd?: string) => string;
|
|
67
67
|
declare class SlatesCliStore {
|
|
68
68
|
readonly rootDir: string;
|
|
69
|
+
readonly cliDir: string;
|
|
69
70
|
readonly dirPath: string;
|
|
70
71
|
readonly storePath: string;
|
|
71
72
|
readonly scope: SlatesCliStoreScope | null;
|
|
72
73
|
readonly data: SlatesCliStoreData;
|
|
73
|
-
constructor(rootDir: string, dirPath: string, storePath: string, scope: SlatesCliStoreScope | null, data: SlatesCliStoreData);
|
|
74
|
+
constructor(rootDir: string, cliDir: string, dirPath: string, storePath: string, scope: SlatesCliStoreScope | null, data: SlatesCliStoreData);
|
|
74
75
|
static open(opts?: {
|
|
75
76
|
cwd?: string;
|
|
77
|
+
rootDir?: string;
|
|
76
78
|
scope?: SlatesCliStoreScope;
|
|
77
79
|
storePath?: string;
|
|
78
80
|
}): Promise<SlatesCliStore>;
|
|
@@ -110,6 +112,7 @@ declare class SlatesCliStore {
|
|
|
110
112
|
}
|
|
111
113
|
declare let openSlatesCliStore: (opts?: {
|
|
112
114
|
cwd?: string;
|
|
115
|
+
rootDir?: string;
|
|
113
116
|
scope?: SlatesCliStoreScope;
|
|
114
117
|
storePath?: string;
|
|
115
118
|
}) => Promise<SlatesCliStore>;
|
|
@@ -117,6 +120,7 @@ declare let openSlatesCliStore: (opts?: {
|
|
|
117
120
|
declare let createSlatesClientFromProfile: (profile: SlatesProfileRecord, opts?: {
|
|
118
121
|
cwd?: string;
|
|
119
122
|
store?: SlatesCliStore;
|
|
123
|
+
autoRefresh?: boolean;
|
|
120
124
|
}) => Promise<_slates_client.SlatesProtocolClient>;
|
|
121
125
|
|
|
122
126
|
export { SlatesCliStore, type SlatesCliStoreData, type SlatesCliStoreScope, type SlatesLocalProfileTarget, type SlatesOAuthCredentialRecord, type SlatesProfileRecord, type SlatesProfileTarget, type SlatesStoredAuth, createSlatesClientFromProfile, openSlatesCliStore, resolveSlatesCliDir, resolveSlatesCliProfilesDir, resolveSlatesCliRoot };
|
package/dist/index.d.ts
CHANGED
|
@@ -66,13 +66,15 @@ declare let resolveSlatesCliDir: (cwd?: string) => string;
|
|
|
66
66
|
declare let resolveSlatesCliProfilesDir: (cwd?: string) => string;
|
|
67
67
|
declare class SlatesCliStore {
|
|
68
68
|
readonly rootDir: string;
|
|
69
|
+
readonly cliDir: string;
|
|
69
70
|
readonly dirPath: string;
|
|
70
71
|
readonly storePath: string;
|
|
71
72
|
readonly scope: SlatesCliStoreScope | null;
|
|
72
73
|
readonly data: SlatesCliStoreData;
|
|
73
|
-
constructor(rootDir: string, dirPath: string, storePath: string, scope: SlatesCliStoreScope | null, data: SlatesCliStoreData);
|
|
74
|
+
constructor(rootDir: string, cliDir: string, dirPath: string, storePath: string, scope: SlatesCliStoreScope | null, data: SlatesCliStoreData);
|
|
74
75
|
static open(opts?: {
|
|
75
76
|
cwd?: string;
|
|
77
|
+
rootDir?: string;
|
|
76
78
|
scope?: SlatesCliStoreScope;
|
|
77
79
|
storePath?: string;
|
|
78
80
|
}): Promise<SlatesCliStore>;
|
|
@@ -110,6 +112,7 @@ declare class SlatesCliStore {
|
|
|
110
112
|
}
|
|
111
113
|
declare let openSlatesCliStore: (opts?: {
|
|
112
114
|
cwd?: string;
|
|
115
|
+
rootDir?: string;
|
|
113
116
|
scope?: SlatesCliStoreScope;
|
|
114
117
|
storePath?: string;
|
|
115
118
|
}) => Promise<SlatesCliStore>;
|
|
@@ -117,6 +120,7 @@ declare let openSlatesCliStore: (opts?: {
|
|
|
117
120
|
declare let createSlatesClientFromProfile: (profile: SlatesProfileRecord, opts?: {
|
|
118
121
|
cwd?: string;
|
|
119
122
|
store?: SlatesCliStore;
|
|
123
|
+
autoRefresh?: boolean;
|
|
120
124
|
}) => Promise<_slates_client.SlatesProtocolClient>;
|
|
121
125
|
|
|
122
126
|
export { SlatesCliStore, type SlatesCliStoreData, type SlatesCliStoreScope, type SlatesLocalProfileTarget, type SlatesOAuthCredentialRecord, type SlatesProfileRecord, type SlatesProfileTarget, type SlatesStoredAuth, createSlatesClientFromProfile, openSlatesCliStore, resolveSlatesCliDir, resolveSlatesCliProfilesDir, resolveSlatesCliRoot };
|
package/dist/index.module.js
CHANGED
|
@@ -41,11 +41,13 @@ var resolveSlatesCliRoot = (cwd = process.cwd()) => {
|
|
|
41
41
|
return cwd;
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
-
var
|
|
45
|
-
var
|
|
44
|
+
var resolveSlatesCliDirFromRoot = (rootDir) => path.join(rootDir, CLI_DIR_NAME);
|
|
45
|
+
var resolveSlatesCliProfilesDirFromRoot = (rootDir) => path.join(resolveSlatesCliDirFromRoot(rootDir), PROFILES_DIR_NAME);
|
|
46
|
+
var resolveSlatesCliDir = (cwd = process.cwd()) => resolveSlatesCliDirFromRoot(resolveSlatesCliRoot(cwd));
|
|
47
|
+
var resolveSlatesCliProfilesDir = (cwd = process.cwd()) => resolveSlatesCliProfilesDirFromRoot(resolveSlatesCliRoot(cwd));
|
|
46
48
|
var normalizeScopeKey = (scopeKey) => path.posix.normalize(scopeKey.replace(/\\/g, "/")).replace(/^\.?\//, "");
|
|
47
49
|
var splitScopeKey = (scopeKey) => normalizeScopeKey(scopeKey).split("/").filter(Boolean).filter((segment) => segment !== "." && segment !== "..");
|
|
48
|
-
var resolveScopedStoreDir = (rootDir, scopeKey) => path.join(
|
|
50
|
+
var resolveScopedStoreDir = (rootDir, scopeKey) => path.join(resolveSlatesCliProfilesDirFromRoot(rootDir), ...splitScopeKey(scopeKey));
|
|
49
51
|
var resolveScopedStorePath = (rootDir, scopeKey) => path.join(resolveScopedStoreDir(rootDir, scopeKey), STORE_FILE_NAME);
|
|
50
52
|
var inferRootDirFromStorePath = (storePath) => {
|
|
51
53
|
let normalized = path.resolve(storePath);
|
|
@@ -58,7 +60,7 @@ var inferRootDirFromStorePath = (storePath) => {
|
|
|
58
60
|
return path.join(path.sep, ...rootParts);
|
|
59
61
|
};
|
|
60
62
|
var resolveScopeKeyFromStorePath = (rootDir, storePath) => {
|
|
61
|
-
let profilesDir =
|
|
63
|
+
let profilesDir = resolveSlatesCliProfilesDirFromRoot(rootDir);
|
|
62
64
|
let relativeDir = path.relative(profilesDir, path.dirname(storePath));
|
|
63
65
|
if (!relativeDir || relativeDir.startsWith("..") || path.isAbsolute(relativeDir)) {
|
|
64
66
|
return null;
|
|
@@ -89,7 +91,7 @@ var isProfileInScope = (rootDir, scopeKey, profile) => {
|
|
|
89
91
|
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
90
92
|
};
|
|
91
93
|
var loadMigratedLegacyStore = async (rootDir, scopeKey) => {
|
|
92
|
-
let legacyStorePath = path.join(
|
|
94
|
+
let legacyStorePath = path.join(resolveSlatesCliDirFromRoot(rootDir), STORE_FILE_NAME);
|
|
93
95
|
let legacy = await readStoreData(legacyStorePath);
|
|
94
96
|
if (!legacy) {
|
|
95
97
|
return createEmptyStore();
|
|
@@ -108,22 +110,25 @@ var loadMigratedLegacyStore = async (rootDir, scopeKey) => {
|
|
|
108
110
|
};
|
|
109
111
|
};
|
|
110
112
|
var SlatesCliStore = class _SlatesCliStore {
|
|
111
|
-
constructor(rootDir, dirPath, storePath, scope, data) {
|
|
113
|
+
constructor(rootDir, cliDir, dirPath, storePath, scope, data) {
|
|
112
114
|
this.rootDir = rootDir;
|
|
115
|
+
this.cliDir = cliDir;
|
|
113
116
|
this.dirPath = dirPath;
|
|
114
117
|
this.storePath = storePath;
|
|
115
118
|
this.scope = scope;
|
|
116
119
|
this.data = data;
|
|
117
120
|
}
|
|
118
121
|
rootDir;
|
|
122
|
+
cliDir;
|
|
119
123
|
dirPath;
|
|
120
124
|
storePath;
|
|
121
125
|
scope;
|
|
122
126
|
data;
|
|
123
127
|
static async open(opts = {}) {
|
|
124
|
-
let
|
|
125
|
-
let
|
|
126
|
-
let
|
|
128
|
+
let storageRootDir = opts.storePath ? inferRootDirFromStorePath(opts.storePath) : resolveSlatesCliRoot(opts.cwd);
|
|
129
|
+
let rootDir = opts.rootDir ?? storageRootDir;
|
|
130
|
+
let cliDir = resolveSlatesCliDirFromRoot(storageRootDir);
|
|
131
|
+
let scopeKey = opts.storePath ? resolveScopeKeyFromStorePath(storageRootDir, opts.storePath) : opts.scope?.key ? normalizeScopeKey(opts.scope.key) : null;
|
|
127
132
|
let dirPath = opts.storePath ? path.dirname(opts.storePath) : scopeKey ? resolveScopedStoreDir(rootDir, scopeKey) : cliDir;
|
|
128
133
|
let storePath = opts.storePath ?? (scopeKey ? resolveScopedStorePath(rootDir, scopeKey) : path.join(cliDir, STORE_FILE_NAME));
|
|
129
134
|
await ensureDir(cliDir);
|
|
@@ -135,12 +140,13 @@ var SlatesCliStore = class _SlatesCliStore {
|
|
|
135
140
|
currentProfileId: parsed.currentProfileId ?? null,
|
|
136
141
|
profiles: parsed.profiles ?? {},
|
|
137
142
|
oauthCredentials: parsed.oauthCredentials ?? {}
|
|
138
|
-
} : scopeKey ? await loadMigratedLegacyStore(rootDir, scopeKey) : createEmptyStore();
|
|
143
|
+
} : opts.storePath ? createEmptyStore() : scopeKey ? await loadMigratedLegacyStore(rootDir, scopeKey) : createEmptyStore();
|
|
139
144
|
if (!parsed) {
|
|
140
145
|
await writeFile(storePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
141
146
|
}
|
|
142
147
|
return new _SlatesCliStore(
|
|
143
148
|
rootDir,
|
|
149
|
+
cliDir,
|
|
144
150
|
dirPath,
|
|
145
151
|
storePath,
|
|
146
152
|
scopeKey ? { key: scopeKey, name: opts.scope?.name } : null,
|
|
@@ -149,8 +155,8 @@ var SlatesCliStore = class _SlatesCliStore {
|
|
|
149
155
|
}
|
|
150
156
|
async save() {
|
|
151
157
|
await ensureDir(this.dirPath);
|
|
152
|
-
await ensureDir(
|
|
153
|
-
await ensureGitIgnore(
|
|
158
|
+
await ensureDir(this.cliDir);
|
|
159
|
+
await ensureGitIgnore(this.cliDir);
|
|
154
160
|
await writeFile(this.storePath, JSON.stringify(this.data, null, 2) + "\n", "utf-8");
|
|
155
161
|
}
|
|
156
162
|
listProfiles() {
|
|
@@ -295,15 +301,18 @@ var SlatesCliStore = class _SlatesCliStore {
|
|
|
295
301
|
var openSlatesCliStore = async (opts = {}) => SlatesCliStore.open(opts);
|
|
296
302
|
|
|
297
303
|
// src/client.ts
|
|
298
|
-
var resolveEntryPath = (entry,
|
|
304
|
+
var resolveEntryPath = (entry, opts = {}) => {
|
|
299
305
|
if (path2.isAbsolute(entry)) return entry;
|
|
300
|
-
return path2.resolve(resolveSlatesCliRoot(cwd), entry);
|
|
306
|
+
return path2.resolve(opts.rootDir ?? resolveSlatesCliRoot(opts.cwd), entry);
|
|
301
307
|
};
|
|
302
|
-
var loadSlateFromProfile = async (profile,
|
|
308
|
+
var loadSlateFromProfile = async (profile, opts = {}) => {
|
|
303
309
|
if (profile.target.type !== "local") {
|
|
304
310
|
throw new Error(`Unsupported profile target type: ${profile.target.type}`);
|
|
305
311
|
}
|
|
306
|
-
let modulePath = resolveEntryPath(profile.target.entry,
|
|
312
|
+
let modulePath = resolveEntryPath(profile.target.entry, {
|
|
313
|
+
cwd: opts.cwd,
|
|
314
|
+
rootDir: opts.store?.rootDir
|
|
315
|
+
});
|
|
307
316
|
let loaded = await import(pathToFileURL(modulePath).href);
|
|
308
317
|
let exportName = profile.target.exportName;
|
|
309
318
|
let slate = (exportName ? loaded[exportName] : void 0) ?? loaded.provider ?? loaded.slate ?? loaded.default;
|
|
@@ -316,7 +325,7 @@ var loadSlateFromProfile = async (profile, cwd) => {
|
|
|
316
325
|
};
|
|
317
326
|
var createSlatesClientFromProfile = async (profile, opts = {}) => {
|
|
318
327
|
let firstAuth = Object.values(profile.auth)[0];
|
|
319
|
-
let slate = await loadSlateFromProfile(profile, opts
|
|
328
|
+
let slate = await loadSlateFromProfile(profile, opts);
|
|
320
329
|
let client = createSlatesClient({
|
|
321
330
|
transport: createLocalSlateTransport({ slate }),
|
|
322
331
|
state: {
|
|
@@ -328,20 +337,25 @@ var createSlatesClientFromProfile = async (profile, opts = {}) => {
|
|
|
328
337
|
} : null
|
|
329
338
|
}
|
|
330
339
|
});
|
|
331
|
-
if (firstAuth) {
|
|
340
|
+
if (firstAuth && opts.autoRefresh !== false) {
|
|
332
341
|
attachAutoRefresh(client, profile, firstAuth, opts.store);
|
|
333
342
|
}
|
|
334
343
|
return client;
|
|
335
344
|
};
|
|
336
345
|
var EXPIRY_BUFFER_MS = 60 * 1e3;
|
|
337
|
-
var
|
|
338
|
-
if (auth.authType !== "auth.oauth") return false;
|
|
339
|
-
if (!auth.clientId || !auth.clientSecret) return false;
|
|
340
|
-
if (typeof auth.output?.refreshToken !== "string" || !auth.output.refreshToken) return false;
|
|
346
|
+
var hasExpiredOrExpiringOutput = (auth) => {
|
|
341
347
|
if (typeof auth.output?.expiresAt !== "string" || !auth.output.expiresAt) return false;
|
|
342
348
|
let expiresAt = Date.parse(auth.output.expiresAt);
|
|
343
349
|
return Number.isFinite(expiresAt) && expiresAt <= Date.now() + EXPIRY_BUFFER_MS;
|
|
344
350
|
};
|
|
351
|
+
var shouldRefreshAuth = (auth) => {
|
|
352
|
+
if (!hasExpiredOrExpiringOutput(auth)) return false;
|
|
353
|
+
if (auth.authType === "auth.oauth") {
|
|
354
|
+
if (!auth.clientId || !auth.clientSecret) return false;
|
|
355
|
+
if (typeof auth.output?.refreshToken !== "string" || !auth.output.refreshToken) return false;
|
|
356
|
+
}
|
|
357
|
+
return true;
|
|
358
|
+
};
|
|
345
359
|
var attachAutoRefresh = (client, profile, storedAuth, store) => {
|
|
346
360
|
let baseRequest = client.request.bind(client);
|
|
347
361
|
let inflightRefresh = null;
|
|
@@ -350,7 +364,7 @@ var attachAutoRefresh = (client, profile, storedAuth, store) => {
|
|
|
350
364
|
await inflightRefresh;
|
|
351
365
|
return;
|
|
352
366
|
}
|
|
353
|
-
if (!
|
|
367
|
+
if (!shouldRefreshAuth(storedAuth)) {
|
|
354
368
|
return;
|
|
355
369
|
}
|
|
356
370
|
inflightRefresh = (async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slates/profiles",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"typecheck": "tsc --noEmit"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@slates/client": "1.0.0-rc.
|
|
35
|
-
"@slates/proto": "1.0.0-rc.
|
|
34
|
+
"@slates/client": "1.0.0-rc.7",
|
|
35
|
+
"@slates/proto": "1.0.0-rc.9"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@slates/provider": "1.0.0-rc.
|
|
38
|
+
"@slates/provider": "1.0.0-rc.11",
|
|
39
39
|
"@slates/tsconfig": "1.0.0-rc.1",
|
|
40
40
|
"typescript": "5.8.2",
|
|
41
41
|
"vitest": "^3.1.2",
|
package/src/client.ts
CHANGED
|
@@ -4,17 +4,23 @@ import { pathToFileURL } from 'url';
|
|
|
4
4
|
import { resolveSlatesCliRoot, SlatesCliStore } from './store';
|
|
5
5
|
import { SlatesProfileRecord, SlatesStoredAuth } from './types';
|
|
6
6
|
|
|
7
|
-
let resolveEntryPath = (entry: string, cwd?: string) => {
|
|
7
|
+
let resolveEntryPath = (entry: string, opts: { cwd?: string; rootDir?: string } = {}) => {
|
|
8
8
|
if (path.isAbsolute(entry)) return entry;
|
|
9
|
-
return path.resolve(resolveSlatesCliRoot(cwd), entry);
|
|
9
|
+
return path.resolve(opts.rootDir ?? resolveSlatesCliRoot(opts.cwd), entry);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
let loadSlateFromProfile = async (
|
|
12
|
+
let loadSlateFromProfile = async (
|
|
13
|
+
profile: SlatesProfileRecord,
|
|
14
|
+
opts: { cwd?: string; store?: SlatesCliStore } = {}
|
|
15
|
+
) => {
|
|
13
16
|
if (profile.target.type !== 'local') {
|
|
14
17
|
throw new Error(`Unsupported profile target type: ${(profile.target as any).type}`);
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
let modulePath = resolveEntryPath(profile.target.entry,
|
|
20
|
+
let modulePath = resolveEntryPath(profile.target.entry, {
|
|
21
|
+
cwd: opts.cwd,
|
|
22
|
+
rootDir: opts.store?.rootDir
|
|
23
|
+
});
|
|
18
24
|
let loaded = await import(pathToFileURL(modulePath).href);
|
|
19
25
|
let exportName = profile.target.exportName;
|
|
20
26
|
|
|
@@ -37,10 +43,10 @@ let loadSlateFromProfile = async (profile: SlatesProfileRecord, cwd?: string) =>
|
|
|
37
43
|
|
|
38
44
|
export let createSlatesClientFromProfile = async (
|
|
39
45
|
profile: SlatesProfileRecord,
|
|
40
|
-
opts: { cwd?: string; store?: SlatesCliStore } = {}
|
|
46
|
+
opts: { cwd?: string; store?: SlatesCliStore; autoRefresh?: boolean } = {}
|
|
41
47
|
) => {
|
|
42
48
|
let firstAuth = Object.values(profile.auth)[0];
|
|
43
|
-
let slate = await loadSlateFromProfile(profile, opts
|
|
49
|
+
let slate = await loadSlateFromProfile(profile, opts);
|
|
44
50
|
let client = createSlatesClient({
|
|
45
51
|
transport: createLocalSlateTransport({ slate }),
|
|
46
52
|
state: {
|
|
@@ -55,7 +61,7 @@ export let createSlatesClientFromProfile = async (
|
|
|
55
61
|
}
|
|
56
62
|
});
|
|
57
63
|
|
|
58
|
-
if (firstAuth) {
|
|
64
|
+
if (firstAuth && opts.autoRefresh !== false) {
|
|
59
65
|
attachAutoRefresh(client, profile, firstAuth, opts.store);
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -64,16 +70,24 @@ export let createSlatesClientFromProfile = async (
|
|
|
64
70
|
|
|
65
71
|
let EXPIRY_BUFFER_MS = 60 * 1000;
|
|
66
72
|
|
|
67
|
-
let
|
|
68
|
-
if (auth.authType !== 'auth.oauth') return false;
|
|
69
|
-
if (!auth.clientId || !auth.clientSecret) return false;
|
|
70
|
-
if (typeof auth.output?.refreshToken !== 'string' || !auth.output.refreshToken) return false;
|
|
73
|
+
let hasExpiredOrExpiringOutput = (auth: SlatesStoredAuth) => {
|
|
71
74
|
if (typeof auth.output?.expiresAt !== 'string' || !auth.output.expiresAt) return false;
|
|
72
75
|
|
|
73
76
|
let expiresAt = Date.parse(auth.output.expiresAt);
|
|
74
77
|
return Number.isFinite(expiresAt) && expiresAt <= Date.now() + EXPIRY_BUFFER_MS;
|
|
75
78
|
};
|
|
76
79
|
|
|
80
|
+
let shouldRefreshAuth = (auth: SlatesStoredAuth) => {
|
|
81
|
+
if (!hasExpiredOrExpiringOutput(auth)) return false;
|
|
82
|
+
|
|
83
|
+
if (auth.authType === 'auth.oauth') {
|
|
84
|
+
if (!auth.clientId || !auth.clientSecret) return false;
|
|
85
|
+
if (typeof auth.output?.refreshToken !== 'string' || !auth.output.refreshToken) return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return true;
|
|
89
|
+
};
|
|
90
|
+
|
|
77
91
|
let attachAutoRefresh = (
|
|
78
92
|
client: ReturnType<typeof createSlatesClient>,
|
|
79
93
|
profile: SlatesProfileRecord,
|
|
@@ -89,7 +103,7 @@ let attachAutoRefresh = (
|
|
|
89
103
|
return;
|
|
90
104
|
}
|
|
91
105
|
|
|
92
|
-
if (!
|
|
106
|
+
if (!shouldRefreshAuth(storedAuth)) {
|
|
93
107
|
return;
|
|
94
108
|
}
|
|
95
109
|
|
package/src/store.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, mkdtemp, rm, writeFile } from 'fs/promises';
|
|
1
|
+
import { access, mkdir, mkdtemp, rm, writeFile } from 'fs/promises';
|
|
2
2
|
import { tmpdir } from 'os';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
@@ -55,9 +55,54 @@ describe('@slates/profiles store', () => {
|
|
|
55
55
|
expect(reopenedProfile.config).toEqual({ prefix: 'Hello' });
|
|
56
56
|
expect(reopened.getAuth(profile.id, 'token_auth')?.output).toEqual({ token: 'abc' });
|
|
57
57
|
expect(reopened.scope?.key).toBe('integrations/demo');
|
|
58
|
+
expect(reopened.cliDir).toBe(path.join(cwd, '.slates-cli'));
|
|
58
59
|
expect(reopened.storePath).toBe(path.join(cwd, '.slates-cli', 'profiles', 'integrations', 'demo', 'store.json'));
|
|
59
60
|
});
|
|
60
61
|
|
|
62
|
+
it('opens an external scoped store with a separate logical root', async () => {
|
|
63
|
+
let workspaceRoot = await createTempDir();
|
|
64
|
+
let storageRoot = await createTempDir();
|
|
65
|
+
let storePath = path.join(
|
|
66
|
+
storageRoot,
|
|
67
|
+
'.slates-cli',
|
|
68
|
+
'profiles',
|
|
69
|
+
'integrations',
|
|
70
|
+
'demo',
|
|
71
|
+
'store.json'
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
let store = await SlatesCliStore.open({
|
|
75
|
+
storePath,
|
|
76
|
+
rootDir: workspaceRoot
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
let profile = store.upsertProfile({
|
|
80
|
+
name: 'Demo',
|
|
81
|
+
target: {
|
|
82
|
+
type: 'local',
|
|
83
|
+
entry: 'integrations/demo/src/index.ts',
|
|
84
|
+
exportName: 'provider'
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
store.setCurrentProfile(profile.id);
|
|
88
|
+
await store.save();
|
|
89
|
+
|
|
90
|
+
let reopened = await SlatesCliStore.open({
|
|
91
|
+
storePath,
|
|
92
|
+
rootDir: workspaceRoot
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(reopened.rootDir).toBe(workspaceRoot);
|
|
96
|
+
expect(reopened.cliDir).toBe(path.join(storageRoot, '.slates-cli'));
|
|
97
|
+
expect(reopened.scope?.key).toBe('integrations/demo');
|
|
98
|
+
expect(reopened.getProfile()?.target.entry).toBe('integrations/demo/src/index.ts');
|
|
99
|
+
|
|
100
|
+
await expect(access(path.join(storageRoot, '.slates-cli', '.gitignore'))).resolves.toBeUndefined();
|
|
101
|
+
await expect(access(path.join(workspaceRoot, '.slates-cli'))).rejects.toMatchObject({
|
|
102
|
+
code: 'ENOENT'
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
61
106
|
it('migrates matching legacy profiles into an integration-scoped store', async () => {
|
|
62
107
|
let cwd = await createTempDir();
|
|
63
108
|
let cliDir = path.join(cwd, '.slates-cli');
|
|
@@ -182,6 +227,62 @@ export let provider = Slate.create({
|
|
|
182
227
|
expect(provider.provider.name).toBe('Demo Slate');
|
|
183
228
|
});
|
|
184
229
|
|
|
230
|
+
it('resolves profile entry paths against the store root when the store lives elsewhere', async () => {
|
|
231
|
+
let workspaceRoot = await createTempDir();
|
|
232
|
+
let storageRoot = await createTempDir();
|
|
233
|
+
let entry = path.join(workspaceRoot, 'integrations', 'demo-slate.mjs');
|
|
234
|
+
await mkdir(path.dirname(entry), { recursive: true });
|
|
235
|
+
await writeFile(
|
|
236
|
+
entry,
|
|
237
|
+
`
|
|
238
|
+
import { Slate, SlateAuth, SlateConfig, SlateSpecification } from '@slates/provider';
|
|
239
|
+
import { z } from 'zod';
|
|
240
|
+
|
|
241
|
+
let config = SlateConfig.create(z.object({})).getDefaultConfig(() => ({}));
|
|
242
|
+
let auth = SlateAuth.create();
|
|
243
|
+
|
|
244
|
+
export let provider = Slate.create({
|
|
245
|
+
spec: SlateSpecification.create({
|
|
246
|
+
key: 'external-demo',
|
|
247
|
+
name: 'External Demo',
|
|
248
|
+
description: 'Store root resolution test',
|
|
249
|
+
config,
|
|
250
|
+
auth
|
|
251
|
+
}),
|
|
252
|
+
tools: [],
|
|
253
|
+
triggers: []
|
|
254
|
+
});
|
|
255
|
+
`,
|
|
256
|
+
'utf-8'
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
let store = await SlatesCliStore.open({
|
|
260
|
+
storePath: path.join(
|
|
261
|
+
storageRoot,
|
|
262
|
+
'.slates-cli',
|
|
263
|
+
'profiles',
|
|
264
|
+
'integrations',
|
|
265
|
+
'demo',
|
|
266
|
+
'store.json'
|
|
267
|
+
),
|
|
268
|
+
rootDir: workspaceRoot
|
|
269
|
+
});
|
|
270
|
+
let profile = store.upsertProfile({
|
|
271
|
+
name: 'Demo',
|
|
272
|
+
target: {
|
|
273
|
+
type: 'local',
|
|
274
|
+
entry: 'integrations/demo-slate.mjs',
|
|
275
|
+
exportName: 'provider'
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
let client = await createSlatesClientFromProfile(profile, { store });
|
|
280
|
+
let provider = await client.identify();
|
|
281
|
+
|
|
282
|
+
expect(provider.provider.id).toBe('external-demo');
|
|
283
|
+
expect(provider.provider.name).toBe('External Demo');
|
|
284
|
+
});
|
|
285
|
+
|
|
185
286
|
it('stores OAuth client credentials per integration', async () => {
|
|
186
287
|
let cwd = await createTempDir();
|
|
187
288
|
let store = await SlatesCliStore.open({
|
|
@@ -312,4 +413,115 @@ export let provider = Slate.create({
|
|
|
312
413
|
token: 'expired-token-refreshed'
|
|
313
414
|
});
|
|
314
415
|
});
|
|
416
|
+
|
|
417
|
+
it('refreshes expired custom auth automatically in the profile-backed client', async () => {
|
|
418
|
+
let cwd = await createTempDir();
|
|
419
|
+
let entry = path.join(cwd, 'custom-slate.mjs');
|
|
420
|
+
await writeFile(
|
|
421
|
+
entry,
|
|
422
|
+
`
|
|
423
|
+
import { Slate, SlateAuth, SlateConfig, SlateSpecification, SlateTool } from '@slates/provider';
|
|
424
|
+
import { z } from 'zod';
|
|
425
|
+
|
|
426
|
+
let config = SlateConfig.create(z.object({})).getDefaultConfig(() => ({}));
|
|
427
|
+
let auth = SlateAuth.create()
|
|
428
|
+
.output(
|
|
429
|
+
z.object({
|
|
430
|
+
token: z.string(),
|
|
431
|
+
expiresAt: z.string().optional()
|
|
432
|
+
})
|
|
433
|
+
)
|
|
434
|
+
.addCustomAuth({
|
|
435
|
+
type: 'auth.custom',
|
|
436
|
+
key: 'custom',
|
|
437
|
+
name: 'Custom',
|
|
438
|
+
inputSchema: z.object({
|
|
439
|
+
tokenPrefix: z.string()
|
|
440
|
+
}),
|
|
441
|
+
getOutput: async ctx => ({
|
|
442
|
+
output: {
|
|
443
|
+
token: \`\${ctx.input.tokenPrefix}-initial\`,
|
|
444
|
+
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString()
|
|
445
|
+
}
|
|
446
|
+
}),
|
|
447
|
+
handleTokenRefresh: async ctx => ({
|
|
448
|
+
output: {
|
|
449
|
+
token: \`\${ctx.input.tokenPrefix}-refreshed\`,
|
|
450
|
+
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString()
|
|
451
|
+
}
|
|
452
|
+
})
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
let spec = SlateSpecification.create({
|
|
456
|
+
key: 'custom-demo',
|
|
457
|
+
name: 'Custom Demo',
|
|
458
|
+
description: 'Custom auth test slate',
|
|
459
|
+
config,
|
|
460
|
+
auth
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
let tool = SlateTool.create(spec, {
|
|
464
|
+
key: 'whoami',
|
|
465
|
+
name: 'Who Am I'
|
|
466
|
+
})
|
|
467
|
+
.input(z.object({}))
|
|
468
|
+
.output(
|
|
469
|
+
z.object({
|
|
470
|
+
token: z.string()
|
|
471
|
+
})
|
|
472
|
+
)
|
|
473
|
+
.handleInvocation(async ctx => ({
|
|
474
|
+
output: {
|
|
475
|
+
token: ctx.auth.token
|
|
476
|
+
}
|
|
477
|
+
}))
|
|
478
|
+
.build();
|
|
479
|
+
|
|
480
|
+
export let provider = Slate.create({
|
|
481
|
+
spec,
|
|
482
|
+
tools: [tool],
|
|
483
|
+
triggers: []
|
|
484
|
+
});
|
|
485
|
+
`,
|
|
486
|
+
'utf-8'
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
let store = await SlatesCliStore.open({
|
|
490
|
+
cwd,
|
|
491
|
+
scope: {
|
|
492
|
+
key: 'integrations/demo',
|
|
493
|
+
name: 'demo'
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
let profile = store.upsertProfile({
|
|
497
|
+
name: 'Demo',
|
|
498
|
+
target: {
|
|
499
|
+
type: 'local',
|
|
500
|
+
entry: './custom-slate.mjs',
|
|
501
|
+
exportName: 'provider'
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
store.setProfileConfig(profile.id, {});
|
|
505
|
+
store.upsertAuth(profile.id, {
|
|
506
|
+
authMethodId: 'custom',
|
|
507
|
+
authType: 'auth.custom',
|
|
508
|
+
input: {
|
|
509
|
+
tokenPrefix: 'custom-token'
|
|
510
|
+
},
|
|
511
|
+
output: {
|
|
512
|
+
token: 'expired-token',
|
|
513
|
+
expiresAt: new Date(Date.now() - 60 * 1000).toISOString()
|
|
514
|
+
},
|
|
515
|
+
scopes: []
|
|
516
|
+
});
|
|
517
|
+
await store.save();
|
|
518
|
+
|
|
519
|
+
let client = await createSlatesClientFromProfile(profile, { cwd, store });
|
|
520
|
+
let result = await client.invokeTool('whoami', {});
|
|
521
|
+
|
|
522
|
+
expect(result.output).toEqual({ token: 'custom-token-refreshed' });
|
|
523
|
+
expect(store.getAuth(profile.id, 'custom')?.output).toMatchObject({
|
|
524
|
+
token: 'custom-token-refreshed'
|
|
525
|
+
});
|
|
526
|
+
});
|
|
315
527
|
});
|
package/src/store.ts
CHANGED
|
@@ -56,11 +56,16 @@ export let resolveSlatesCliRoot = (cwd: string = process.cwd()) => {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
let resolveSlatesCliDirFromRoot = (rootDir: string) => path.join(rootDir, CLI_DIR_NAME);
|
|
60
|
+
|
|
61
|
+
let resolveSlatesCliProfilesDirFromRoot = (rootDir: string) =>
|
|
62
|
+
path.join(resolveSlatesCliDirFromRoot(rootDir), PROFILES_DIR_NAME);
|
|
63
|
+
|
|
59
64
|
export let resolveSlatesCliDir = (cwd: string = process.cwd()) =>
|
|
60
|
-
|
|
65
|
+
resolveSlatesCliDirFromRoot(resolveSlatesCliRoot(cwd));
|
|
61
66
|
|
|
62
67
|
export let resolveSlatesCliProfilesDir = (cwd: string = process.cwd()) =>
|
|
63
|
-
|
|
68
|
+
resolveSlatesCliProfilesDirFromRoot(resolveSlatesCliRoot(cwd));
|
|
64
69
|
|
|
65
70
|
let normalizeScopeKey = (scopeKey: string) =>
|
|
66
71
|
path.posix.normalize(scopeKey.replace(/\\/g, '/')).replace(/^\.?\//, '');
|
|
@@ -72,7 +77,7 @@ let splitScopeKey = (scopeKey: string) =>
|
|
|
72
77
|
.filter(segment => segment !== '.' && segment !== '..');
|
|
73
78
|
|
|
74
79
|
let resolveScopedStoreDir = (rootDir: string, scopeKey: string) =>
|
|
75
|
-
path.join(
|
|
80
|
+
path.join(resolveSlatesCliProfilesDirFromRoot(rootDir), ...splitScopeKey(scopeKey));
|
|
76
81
|
|
|
77
82
|
let resolveScopedStorePath = (rootDir: string, scopeKey: string) =>
|
|
78
83
|
path.join(resolveScopedStoreDir(rootDir, scopeKey), STORE_FILE_NAME);
|
|
@@ -91,7 +96,7 @@ let inferRootDirFromStorePath = (storePath: string) => {
|
|
|
91
96
|
};
|
|
92
97
|
|
|
93
98
|
let resolveScopeKeyFromStorePath = (rootDir: string, storePath: string) => {
|
|
94
|
-
let profilesDir =
|
|
99
|
+
let profilesDir = resolveSlatesCliProfilesDirFromRoot(rootDir);
|
|
95
100
|
let relativeDir = path.relative(profilesDir, path.dirname(storePath));
|
|
96
101
|
if (!relativeDir || relativeDir.startsWith('..') || path.isAbsolute(relativeDir)) {
|
|
97
102
|
return null;
|
|
@@ -138,7 +143,7 @@ let loadMigratedLegacyStore = async (
|
|
|
138
143
|
rootDir: string,
|
|
139
144
|
scopeKey: string
|
|
140
145
|
): Promise<SlatesCliStoreData> => {
|
|
141
|
-
let legacyStorePath = path.join(
|
|
146
|
+
let legacyStorePath = path.join(resolveSlatesCliDirFromRoot(rootDir), STORE_FILE_NAME);
|
|
142
147
|
let legacy = await readStoreData<SlatesLegacyCliStoreData>(legacyStorePath);
|
|
143
148
|
if (!legacy) {
|
|
144
149
|
return createEmptyStore();
|
|
@@ -166,6 +171,7 @@ let loadMigratedLegacyStore = async (
|
|
|
166
171
|
export class SlatesCliStore {
|
|
167
172
|
constructor(
|
|
168
173
|
readonly rootDir: string,
|
|
174
|
+
readonly cliDir: string,
|
|
169
175
|
readonly dirPath: string,
|
|
170
176
|
readonly storePath: string,
|
|
171
177
|
readonly scope: SlatesCliStoreScope | null,
|
|
@@ -173,14 +179,15 @@ export class SlatesCliStore {
|
|
|
173
179
|
) {}
|
|
174
180
|
|
|
175
181
|
static async open(
|
|
176
|
-
opts: { cwd?: string; scope?: SlatesCliStoreScope; storePath?: string } = {}
|
|
182
|
+
opts: { cwd?: string; rootDir?: string; scope?: SlatesCliStoreScope; storePath?: string } = {}
|
|
177
183
|
) {
|
|
178
|
-
let
|
|
184
|
+
let storageRootDir = opts.storePath
|
|
179
185
|
? inferRootDirFromStorePath(opts.storePath)
|
|
180
186
|
: resolveSlatesCliRoot(opts.cwd);
|
|
181
|
-
let
|
|
187
|
+
let rootDir = opts.rootDir ?? storageRootDir;
|
|
188
|
+
let cliDir = resolveSlatesCliDirFromRoot(storageRootDir);
|
|
182
189
|
let scopeKey = opts.storePath
|
|
183
|
-
? resolveScopeKeyFromStorePath(
|
|
190
|
+
? resolveScopeKeyFromStorePath(storageRootDir, opts.storePath)
|
|
184
191
|
: opts.scope?.key
|
|
185
192
|
? normalizeScopeKey(opts.scope.key)
|
|
186
193
|
: null;
|
|
@@ -207,6 +214,8 @@ export class SlatesCliStore {
|
|
|
207
214
|
profiles: parsed.profiles ?? {},
|
|
208
215
|
oauthCredentials: parsed.oauthCredentials ?? {}
|
|
209
216
|
}
|
|
217
|
+
: opts.storePath
|
|
218
|
+
? createEmptyStore()
|
|
210
219
|
: scopeKey
|
|
211
220
|
? await loadMigratedLegacyStore(rootDir, scopeKey)
|
|
212
221
|
: createEmptyStore();
|
|
@@ -217,6 +226,7 @@ export class SlatesCliStore {
|
|
|
217
226
|
|
|
218
227
|
return new SlatesCliStore(
|
|
219
228
|
rootDir,
|
|
229
|
+
cliDir,
|
|
220
230
|
dirPath,
|
|
221
231
|
storePath,
|
|
222
232
|
scopeKey ? { key: scopeKey, name: opts.scope?.name } : null,
|
|
@@ -226,8 +236,8 @@ export class SlatesCliStore {
|
|
|
226
236
|
|
|
227
237
|
async save() {
|
|
228
238
|
await ensureDir(this.dirPath);
|
|
229
|
-
await ensureDir(
|
|
230
|
-
await ensureGitIgnore(
|
|
239
|
+
await ensureDir(this.cliDir);
|
|
240
|
+
await ensureGitIgnore(this.cliDir);
|
|
231
241
|
await writeFile(this.storePath, JSON.stringify(this.data, null, 2) + '\n', 'utf-8');
|
|
232
242
|
}
|
|
233
243
|
|
|
@@ -418,5 +428,10 @@ export class SlatesCliStore {
|
|
|
418
428
|
}
|
|
419
429
|
|
|
420
430
|
export let openSlatesCliStore = async (
|
|
421
|
-
opts: {
|
|
431
|
+
opts: {
|
|
432
|
+
cwd?: string;
|
|
433
|
+
rootDir?: string;
|
|
434
|
+
scope?: SlatesCliStoreScope;
|
|
435
|
+
storePath?: string;
|
|
436
|
+
} = {}
|
|
422
437
|
) => SlatesCliStore.open(opts);
|