@slates/profiles 1.0.0-rc.3 → 1.0.0-rc.4

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 CHANGED
@@ -82,11 +82,13 @@ var resolveSlatesCliRoot = (cwd = process.cwd()) => {
82
82
  return cwd;
83
83
  }
84
84
  };
85
- var resolveSlatesCliDir = (cwd = process.cwd()) => import_path.default.join(resolveSlatesCliRoot(cwd), CLI_DIR_NAME);
86
- var resolveSlatesCliProfilesDir = (cwd = process.cwd()) => import_path.default.join(resolveSlatesCliDir(cwd), PROFILES_DIR_NAME);
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(resolveSlatesCliProfilesDir(rootDir), ...splitScopeKey(scopeKey));
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 = resolveSlatesCliProfilesDir(rootDir);
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(resolveSlatesCliDir(rootDir), STORE_FILE_NAME);
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 rootDir = opts.storePath ? inferRootDirFromStorePath(opts.storePath) : resolveSlatesCliRoot(opts.cwd);
166
- let cliDir = resolveSlatesCliDir(rootDir);
167
- let scopeKey = opts.storePath ? resolveScopeKeyFromStorePath(rootDir, opts.storePath) : opts.scope?.key ? normalizeScopeKey(opts.scope.key) : null;
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(resolveSlatesCliDir(this.rootDir));
194
- await ensureGitIgnore(resolveSlatesCliDir(this.rootDir));
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, cwd) => {
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, cwd) => {
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, cwd);
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.cwd);
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: {
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>;
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>;
@@ -41,11 +41,13 @@ var resolveSlatesCliRoot = (cwd = process.cwd()) => {
41
41
  return cwd;
42
42
  }
43
43
  };
44
- var resolveSlatesCliDir = (cwd = process.cwd()) => path.join(resolveSlatesCliRoot(cwd), CLI_DIR_NAME);
45
- var resolveSlatesCliProfilesDir = (cwd = process.cwd()) => path.join(resolveSlatesCliDir(cwd), PROFILES_DIR_NAME);
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(resolveSlatesCliProfilesDir(rootDir), ...splitScopeKey(scopeKey));
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 = resolveSlatesCliProfilesDir(rootDir);
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(resolveSlatesCliDir(rootDir), STORE_FILE_NAME);
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 rootDir = opts.storePath ? inferRootDirFromStorePath(opts.storePath) : resolveSlatesCliRoot(opts.cwd);
125
- let cliDir = resolveSlatesCliDir(rootDir);
126
- let scopeKey = opts.storePath ? resolveScopeKeyFromStorePath(rootDir, opts.storePath) : opts.scope?.key ? normalizeScopeKey(opts.scope.key) : null;
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(resolveSlatesCliDir(this.rootDir));
153
- await ensureGitIgnore(resolveSlatesCliDir(this.rootDir));
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, cwd) => {
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, cwd) => {
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, cwd);
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.cwd);
328
+ let slate = await loadSlateFromProfile(profile, opts);
320
329
  let client = createSlatesClient({
321
330
  transport: createLocalSlateTransport({ slate }),
322
331
  state: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slates/profiles",
3
- "version": "1.0.0-rc.3",
3
+ "version": "1.0.0-rc.4",
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.3",
34
+ "@slates/client": "1.0.0-rc.6",
35
35
  "@slates/proto": "1.0.0-rc.8"
36
36
  },
37
37
  "devDependencies": {
38
- "@slates/provider": "1.0.0-rc.9",
38
+ "@slates/provider": "1.0.0-rc.10",
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 (profile: SlatesProfileRecord, cwd?: string) => {
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, cwd);
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
 
@@ -40,7 +46,7 @@ export let createSlatesClientFromProfile = async (
40
46
  opts: { cwd?: string; store?: SlatesCliStore } = {}
41
47
  ) => {
42
48
  let firstAuth = Object.values(profile.auth)[0];
43
- let slate = await loadSlateFromProfile(profile, opts.cwd);
49
+ let slate = await loadSlateFromProfile(profile, opts);
44
50
  let client = createSlatesClient({
45
51
  transport: createLocalSlateTransport({ slate }),
46
52
  state: {
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({
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
- path.join(resolveSlatesCliRoot(cwd), CLI_DIR_NAME);
65
+ resolveSlatesCliDirFromRoot(resolveSlatesCliRoot(cwd));
61
66
 
62
67
  export let resolveSlatesCliProfilesDir = (cwd: string = process.cwd()) =>
63
- path.join(resolveSlatesCliDir(cwd), PROFILES_DIR_NAME);
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(resolveSlatesCliProfilesDir(rootDir), ...splitScopeKey(scopeKey));
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 = resolveSlatesCliProfilesDir(rootDir);
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(resolveSlatesCliDir(rootDir), STORE_FILE_NAME);
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 rootDir = opts.storePath
184
+ let storageRootDir = opts.storePath
179
185
  ? inferRootDirFromStorePath(opts.storePath)
180
186
  : resolveSlatesCliRoot(opts.cwd);
181
- let cliDir = resolveSlatesCliDir(rootDir);
187
+ let rootDir = opts.rootDir ?? storageRootDir;
188
+ let cliDir = resolveSlatesCliDirFromRoot(storageRootDir);
182
189
  let scopeKey = opts.storePath
183
- ? resolveScopeKeyFromStorePath(rootDir, opts.storePath)
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(resolveSlatesCliDir(this.rootDir));
230
- await ensureGitIgnore(resolveSlatesCliDir(this.rootDir));
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: { cwd?: string; scope?: SlatesCliStoreScope; storePath?: string } = {}
431
+ opts: {
432
+ cwd?: string;
433
+ rootDir?: string;
434
+ scope?: SlatesCliStoreScope;
435
+ storePath?: string;
436
+ } = {}
422
437
  ) => SlatesCliStore.open(opts);