synomem 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +1 -1
- package/dist/backend.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +53 -13
- package/dist/cli.js.map +1 -1
- package/dist/configure.d.ts +7 -4
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +28 -5
- package/dist/configure.js.map +1 -1
- package/dist/credentials.d.ts +12 -5
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js.map +1 -1
- package/dist/oauth.d.ts +15 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +26 -6
- package/dist/oauth.js.map +1 -1
- package/docs/cli.md +4 -3
- package/package.json +1 -1
- package/src/backend.ts +2 -0
- package/src/cli.ts +55 -14
- package/src/configure.ts +28 -5
- package/src/credentials.ts +12 -5
- package/src/oauth.ts +20 -5
package/dist/credentials.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAC7C,MAAM,kBAAkB,GAAG,GAAG,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth.d.ts
CHANGED
|
@@ -17,10 +17,24 @@ export declare class StoredCredentialProvider implements SynomemCredentialProvid
|
|
|
17
17
|
private readonly store;
|
|
18
18
|
private readonly env;
|
|
19
19
|
private readonly fetchImplementation;
|
|
20
|
+
/**
|
|
21
|
+
* Where `synomem config`'s restricted-file credential store, if chosen,
|
|
22
|
+
* would have written an access key. Optional because local-only and
|
|
23
|
+
* environment-only callers have no such file to fall back to.
|
|
24
|
+
*/
|
|
25
|
+
private readonly home?;
|
|
20
26
|
private refresh?;
|
|
21
27
|
private credential?;
|
|
28
|
+
/** Set when the stored credential is an access key rather than an OAuth grant. */
|
|
29
|
+
private staticAccessToken?;
|
|
22
30
|
private loaded;
|
|
23
|
-
constructor(reference: string, store: CredentialStore, env?: NodeJS.ProcessEnv, fetchImplementation?: typeof fetch
|
|
31
|
+
constructor(reference: string, store: CredentialStore, env?: NodeJS.ProcessEnv, fetchImplementation?: typeof fetch,
|
|
32
|
+
/**
|
|
33
|
+
* Where `synomem config`'s restricted-file credential store, if chosen,
|
|
34
|
+
* would have written an access key. Optional because local-only and
|
|
35
|
+
* environment-only callers have no such file to fall back to.
|
|
36
|
+
*/
|
|
37
|
+
home?: string | undefined);
|
|
24
38
|
getAccessToken(signal?: AbortSignal): Promise<string | undefined>;
|
|
25
39
|
private refreshCredential;
|
|
26
40
|
}
|
package/dist/oauth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAoH7D,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,eAAe,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwD9E;AAED,qBAAa,wBAAyB,YAAW,yBAAyB;IAQtE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IAhBxB,OAAO,CAAC,OAAO,CAAC,CAA8B;IAC9C,OAAO,CAAC,UAAU,CAAC,CAAwB;IAC3C,kFAAkF;IAClF,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,MAAM,CAAS;gBAGJ,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,eAAe,EACtB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,mBAAmB,GAAE,OAAO,KAAa;IAC1D;;;;OAIG;IACc,IAAI,CAAC,EAAE,MAAM,YAAA;IAG1B,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YA6BzD,iBAAiB;CA6BhC"}
|
package/dist/oauth.js
CHANGED
|
@@ -3,6 +3,7 @@ import { spawn } from 'node:child_process';
|
|
|
3
3
|
import { randomBytes } from 'node:crypto';
|
|
4
4
|
import { discoverOAuthServerInfo, startAuthorization, } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
5
5
|
import { SynomemError } from './errors.js';
|
|
6
|
+
import { readCredentialFile } from './configure.js';
|
|
6
7
|
const defaultScope = 'synomem:read synomem:write offline_access';
|
|
7
8
|
function secureEndpoint(value, label) {
|
|
8
9
|
const url = new URL(value);
|
|
@@ -148,14 +149,24 @@ export class StoredCredentialProvider {
|
|
|
148
149
|
store;
|
|
149
150
|
env;
|
|
150
151
|
fetchImplementation;
|
|
152
|
+
home;
|
|
151
153
|
refresh;
|
|
152
154
|
credential;
|
|
155
|
+
/** Set when the stored credential is an access key rather than an OAuth grant. */
|
|
156
|
+
staticAccessToken;
|
|
153
157
|
loaded = false;
|
|
154
|
-
constructor(reference, store, env = process.env, fetchImplementation = fetch
|
|
158
|
+
constructor(reference, store, env = process.env, fetchImplementation = fetch,
|
|
159
|
+
/**
|
|
160
|
+
* Where `synomem config`'s restricted-file credential store, if chosen,
|
|
161
|
+
* would have written an access key. Optional because local-only and
|
|
162
|
+
* environment-only callers have no such file to fall back to.
|
|
163
|
+
*/
|
|
164
|
+
home) {
|
|
155
165
|
this.reference = reference;
|
|
156
166
|
this.store = store;
|
|
157
167
|
this.env = env;
|
|
158
168
|
this.fetchImplementation = fetchImplementation;
|
|
169
|
+
this.home = home;
|
|
159
170
|
}
|
|
160
171
|
async getAccessToken(signal) {
|
|
161
172
|
if (this.env.SYNOMEM_ACCESS_TOKEN)
|
|
@@ -163,14 +174,23 @@ export class StoredCredentialProvider {
|
|
|
163
174
|
if (!this.loaded) {
|
|
164
175
|
const stored = await this.store.get(this.reference);
|
|
165
176
|
/*
|
|
166
|
-
* An
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* ignores it and lets the installation-key path handle it.
|
|
177
|
+
* An access key is not an OAuth credential: it cannot be refreshed and
|
|
178
|
+
* has no client or token endpoint. It is used exactly as stored,
|
|
179
|
+
* whichever of the two places it was found.
|
|
170
180
|
*/
|
|
171
|
-
|
|
181
|
+
if (stored && 'kind' in stored) {
|
|
182
|
+
this.staticAccessToken = stored.accessToken;
|
|
183
|
+
}
|
|
184
|
+
else if (stored) {
|
|
185
|
+
this.credential = stored;
|
|
186
|
+
}
|
|
187
|
+
else if (this.home) {
|
|
188
|
+
this.staticAccessToken = readCredentialFile(this.home);
|
|
189
|
+
}
|
|
172
190
|
this.loaded = true;
|
|
173
191
|
}
|
|
192
|
+
if (this.staticAccessToken)
|
|
193
|
+
return this.staticAccessToken;
|
|
174
194
|
const credential = this.credential;
|
|
175
195
|
if (!credential)
|
|
176
196
|
return undefined;
|
package/dist/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACL,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|
package/docs/cli.md
CHANGED
|
@@ -21,9 +21,10 @@ synomem config init --backend local --yes # the deterministic equivalent
|
|
|
21
21
|
synomem config show # never prints a secret, only where one comes from
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
For Synomem Cloud with an
|
|
25
|
-
|
|
26
|
-
the shell history and
|
|
24
|
+
For Synomem Cloud with an access key, setup asks the key which workspaces its organization has and
|
|
25
|
+
picks one automatically when there is only one — nothing has to be looked up by hand. The key is
|
|
26
|
+
piped rather than passed as an argument, because an argument is kept by both the shell history and
|
|
27
|
+
the process list:
|
|
27
28
|
|
|
28
29
|
```bash
|
|
29
30
|
printf '%s' "$SYNOMEM_KEY" | synomem config init \
|
package/package.json
CHANGED
package/src/backend.ts
CHANGED
|
@@ -88,6 +88,8 @@ export function createConfiguredService(
|
|
|
88
88
|
credentialReference(backend.baseUrl, backend.workspaceId, expectedActor),
|
|
89
89
|
new OsCredentialStore(),
|
|
90
90
|
env,
|
|
91
|
+
fetch,
|
|
92
|
+
resolveHome(options.home),
|
|
91
93
|
),
|
|
92
94
|
...(options.signal ? { signal: options.signal } : {}),
|
|
93
95
|
});
|
package/src/cli.ts
CHANGED
|
@@ -571,12 +571,12 @@ export function createCli(
|
|
|
571
571
|
const remoteCommand = program.command('remote').description('Administer a remote workspace');
|
|
572
572
|
|
|
573
573
|
/*
|
|
574
|
-
* The browser counterpart to
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
574
|
+
* The browser counterpart to `discoverAccessKeyWorkspaces` — same purpose,
|
|
575
|
+
* different credential: a signed-in account may reach several
|
|
576
|
+
* organizations, each with several workspaces, so there is a genuine choice
|
|
577
|
+
* to make, and no way to make it without seeing the list. Printing the IDs
|
|
578
|
+
* alongside the names is the point: the ID is what `backend use remote
|
|
579
|
+
* --workspace` takes.
|
|
580
580
|
*/
|
|
581
581
|
remoteCommand
|
|
582
582
|
.command('workspaces')
|
|
@@ -661,6 +661,8 @@ export function createCli(
|
|
|
661
661
|
credentialReference(backend.baseUrl, backend.workspaceId, administrator),
|
|
662
662
|
credentialStore,
|
|
663
663
|
env,
|
|
664
|
+
fetch,
|
|
665
|
+
resolveHome(global.home),
|
|
664
666
|
);
|
|
665
667
|
const importer = new RemoteImportClient({
|
|
666
668
|
baseUrl: backend.baseUrl,
|
|
@@ -736,6 +738,10 @@ export function createCli(
|
|
|
736
738
|
* person who already knows which one they want should not be asked again.
|
|
737
739
|
*/
|
|
738
740
|
let workspaceId = plan.workspaceId;
|
|
741
|
+
// Only known once discovered below — printed in the final summary rather
|
|
742
|
+
// than the bare ID, so "what did config just do" reads like an answer
|
|
743
|
+
// instead of a lookup key.
|
|
744
|
+
let workspaceName: string | undefined;
|
|
739
745
|
if (plan.backend === 'remote' && !workspaceId && token) {
|
|
740
746
|
const discovered = await discoverWorkspaces({ baseUrl: serviceUrl, accessToken: token });
|
|
741
747
|
if (discovered.workspaces.length === 0) {
|
|
@@ -749,9 +755,7 @@ export function createCli(
|
|
|
749
755
|
);
|
|
750
756
|
} else if (discovered.workspaces.length === 1) {
|
|
751
757
|
workspaceId = discovered.workspaces[0]!.id;
|
|
752
|
-
|
|
753
|
-
`Using this key's only workspace: ${discovered.workspaces[0]!.displayName} (${workspaceId}).\n`,
|
|
754
|
-
);
|
|
758
|
+
workspaceName = discovered.workspaces[0]!.displayName;
|
|
755
759
|
} else if (promptIo.interactive) {
|
|
756
760
|
workspaceId = await select(
|
|
757
761
|
promptIo,
|
|
@@ -762,6 +766,7 @@ export function createCli(
|
|
|
762
766
|
detail: workspace.id,
|
|
763
767
|
})),
|
|
764
768
|
);
|
|
769
|
+
workspaceName = discovered.workspaces.find((w) => w.id === workspaceId)?.displayName;
|
|
765
770
|
} else {
|
|
766
771
|
throw new SynomemError(
|
|
767
772
|
'INVALID_INPUT',
|
|
@@ -840,6 +845,30 @@ export function createCli(
|
|
|
840
845
|
client.doctor(),
|
|
841
846
|
);
|
|
842
847
|
|
|
848
|
+
/*
|
|
849
|
+
* What to do next differs by exactly one thing: whether an agent can be
|
|
850
|
+
* created from here at all. An access key never carries the
|
|
851
|
+
* administrator authority agent creation requires (§ deliberate,
|
|
852
|
+
* independent of the key owner's own role) — local storage and a human
|
|
853
|
+
* browser sign-in both can. Telling everyone to just run `agent create`
|
|
854
|
+
* regardless was the CLI recommending a command guaranteed to fail for
|
|
855
|
+
* the single most common setup path.
|
|
856
|
+
*/
|
|
857
|
+
const canCreateAgentHere = config.backend.kind === 'local' || plan.auth !== 'access-key';
|
|
858
|
+
const nextSteps = canCreateAgentHere
|
|
859
|
+
? [
|
|
860
|
+
' synomem agent create <handle> --name "<display name>"',
|
|
861
|
+
' synomem skill install --runtime <claude|codex|cursor|...> --agent <agent-id>',
|
|
862
|
+
]
|
|
863
|
+
: [
|
|
864
|
+
" An access key can't create an agent — that needs an administrator,",
|
|
865
|
+
" which a key never asserts on its own, regardless of the member's own",
|
|
866
|
+
" role. Create one in the Synomem portal (a workspace's Actors page →",
|
|
867
|
+
' New agent), then use its ID:',
|
|
868
|
+
'',
|
|
869
|
+
' synomem skill install --runtime <claude|codex|cursor|...> --agent <agent-id>',
|
|
870
|
+
];
|
|
871
|
+
|
|
843
872
|
output(
|
|
844
873
|
io,
|
|
845
874
|
global.json,
|
|
@@ -849,18 +878,30 @@ export function createCli(
|
|
|
849
878
|
...(credentialLocation ? { credentialSource: credentialLocation } : {}),
|
|
850
879
|
...(token ? { credential: credentialFingerprint(token) } : {}),
|
|
851
880
|
healthy: diagnostics.healthy,
|
|
881
|
+
canCreateAgentHere,
|
|
852
882
|
},
|
|
853
883
|
[
|
|
854
884
|
'',
|
|
855
885
|
'Synomem is ready.',
|
|
856
886
|
'',
|
|
857
|
-
` Backend:
|
|
858
|
-
` Home:
|
|
887
|
+
` Backend: ${config.backend.kind === 'local' ? 'Local SQLite' : 'Synomem Cloud'}`,
|
|
888
|
+
` Home: ${home}`,
|
|
859
889
|
...(config.backend.kind === 'remote'
|
|
860
|
-
? [
|
|
890
|
+
? [
|
|
891
|
+
` Service: ${config.backend.baseUrl}`,
|
|
892
|
+
` Workspace: ${workspaceName ? `${workspaceName} (${config.backend.workspaceId})` : config.backend.workspaceId}`,
|
|
893
|
+
]
|
|
861
894
|
: []),
|
|
862
895
|
...(credentialLocation ? [` Credential: ${credentialLocation}`] : []),
|
|
863
|
-
` Database:
|
|
896
|
+
` Database: ${diagnostics.healthy ? 'Healthy' : 'Needs attention — run synomem doctor'}`,
|
|
897
|
+
'',
|
|
898
|
+
'Next: set up an agent for this machine.',
|
|
899
|
+
'',
|
|
900
|
+
...nextSteps,
|
|
901
|
+
'',
|
|
902
|
+
'Full walkthrough, including the MCP connector for each platform, and a',
|
|
903
|
+
'prompt that does all of this for you:',
|
|
904
|
+
' https://github.com/Coaden/synomem#let-your-agent-set-it-up',
|
|
864
905
|
].join('\n'),
|
|
865
906
|
);
|
|
866
907
|
};
|
|
@@ -888,7 +929,7 @@ export function createCli(
|
|
|
888
929
|
.option('--credential-store <where>', 'auto, keychain, file, or environment', 'auto')
|
|
889
930
|
// The token is read from stdin, never taken as an argument: an argument is
|
|
890
931
|
// kept by the shell history and visible in the process list.
|
|
891
|
-
.option('--access-token-stdin', 'read the
|
|
932
|
+
.option('--access-token-stdin', 'read the access key from stdin', false)
|
|
892
933
|
.option('--yes', 'apply without confirming', false)
|
|
893
934
|
.action(
|
|
894
935
|
async (
|
package/src/configure.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* that blocks forever on a pipe is worse than one that says which flags it
|
|
8
8
|
* needs.
|
|
9
9
|
*/
|
|
10
|
-
import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import { cloudApiUrl } from './cloud.js';
|
|
13
13
|
import { SynomemError } from './errors.js';
|
|
@@ -117,16 +117,39 @@ export function assertInteractive(io: PromptIo): void {
|
|
|
117
117
|
* Separate from `config.json` so a configuration file can be read, copied or
|
|
118
118
|
* pasted into an issue without carrying a secret with it.
|
|
119
119
|
*/
|
|
120
|
+
function credentialFilePath(home: string): string {
|
|
121
|
+
return join(home, 'credentials', 'installation.json');
|
|
122
|
+
}
|
|
123
|
+
|
|
120
124
|
export function writeCredentialFile(home: string, token: string): string {
|
|
121
125
|
const directory = join(home, 'credentials');
|
|
122
126
|
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
123
127
|
chmodSync(directory, 0o700);
|
|
124
|
-
const path =
|
|
128
|
+
const path = credentialFilePath(home);
|
|
125
129
|
writeFileSync(path, `${JSON.stringify({ accessToken: token }, null, 2)}\n`, { mode: 0o600 });
|
|
126
130
|
chmodSync(path, 0o600);
|
|
127
131
|
return path;
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Reads back what `writeCredentialFile` wrote.
|
|
136
|
+
*
|
|
137
|
+
* Without this, choosing the restricted-file store at `synomem config` wrote
|
|
138
|
+
* a credential nothing ever read again: every later command still asked the
|
|
139
|
+
* OS keychain, found nothing there, and failed with AUTH_REQUIRED even though
|
|
140
|
+
* the key was sitting right there on disk.
|
|
141
|
+
*/
|
|
142
|
+
export function readCredentialFile(home: string): string | undefined {
|
|
143
|
+
const path = credentialFilePath(home);
|
|
144
|
+
if (!existsSync(path)) return undefined;
|
|
145
|
+
try {
|
|
146
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8')) as { accessToken?: unknown };
|
|
147
|
+
return typeof parsed.accessToken === 'string' ? parsed.accessToken : undefined;
|
|
148
|
+
} catch {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
130
153
|
/** A key's identifying prefix. Never the key. */
|
|
131
154
|
export function credentialFingerprint(token: string): string {
|
|
132
155
|
const head = token.slice(0, 12);
|
|
@@ -194,8 +217,8 @@ export async function runConfigWizard(
|
|
|
194
217
|
},
|
|
195
218
|
{
|
|
196
219
|
value: 'access-key',
|
|
197
|
-
label: 'Use an
|
|
198
|
-
detail: 'Create one at https://portal.synomem.ai/
|
|
220
|
+
label: 'Use an access key',
|
|
221
|
+
detail: 'Create one at https://portal.synomem.ai/access-keys/new',
|
|
199
222
|
},
|
|
200
223
|
]);
|
|
201
224
|
|
|
@@ -224,7 +247,7 @@ export async function runConfigWizard(
|
|
|
224
247
|
|
|
225
248
|
/** Reads an access key without ever accepting it as an argument. */
|
|
226
249
|
export async function readAccessToken(io: PromptIo): Promise<string> {
|
|
227
|
-
const token = await askSecret(io, '
|
|
250
|
+
const token = await askSecret(io, 'Access key');
|
|
228
251
|
if (!token) throw new SynomemError('INVALID_INPUT', 'No access key was provided.');
|
|
229
252
|
return token;
|
|
230
253
|
}
|
package/src/credentials.ts
CHANGED
|
@@ -7,12 +7,19 @@ const serviceName = 'ai.synomem.credentials';
|
|
|
7
7
|
const maximumOutputBytes = 128 * 1024;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* A member-owned access key.
|
|
11
11
|
*
|
|
12
|
-
* Not an OAuth credential: it has no refresh, no token endpoint and no
|
|
13
|
-
* and it authorizes
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* Not an OAuth credential: it has no refresh, no token endpoint and no
|
|
13
|
+
* client, and it authorizes the MEMBER who created it, reaching every
|
|
14
|
+
* workspace their organization membership allows -- never a single machine
|
|
15
|
+
* or a single workspace. Keeping it a distinct shape stops code treating it
|
|
16
|
+
* as refreshable, which would mean silently failing to renew something that
|
|
17
|
+
* never expires that way.
|
|
18
|
+
*
|
|
19
|
+
* The `kind` value and this type's own name predate member-owned access
|
|
20
|
+
* keys; both still say "installation" because renaming either changes the
|
|
21
|
+
* shape already written to disk and the OS keychain on every machine that
|
|
22
|
+
* has run `synomem config`, for no behavioral gain.
|
|
16
23
|
*/
|
|
17
24
|
export interface StoredInstallationKey {
|
|
18
25
|
kind: 'installation-key';
|
package/src/oauth.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { SynomemError } from './errors.js';
|
|
9
9
|
import type { CredentialStore, StoredOAuthCredential } from './credentials.js';
|
|
10
10
|
import type { SynomemCredentialProvider } from './remote.js';
|
|
11
|
+
import { readCredentialFile } from './configure.js';
|
|
11
12
|
|
|
12
13
|
const defaultScope = 'synomem:read synomem:write offline_access';
|
|
13
14
|
|
|
@@ -195,6 +196,8 @@ export async function loginWithOAuth(options: OAuthLoginOptions): Promise<void>
|
|
|
195
196
|
export class StoredCredentialProvider implements SynomemCredentialProvider {
|
|
196
197
|
private refresh?: Promise<string | undefined>;
|
|
197
198
|
private credential?: StoredOAuthCredential;
|
|
199
|
+
/** Set when the stored credential is an access key rather than an OAuth grant. */
|
|
200
|
+
private staticAccessToken?: string;
|
|
198
201
|
private loaded = false;
|
|
199
202
|
|
|
200
203
|
constructor(
|
|
@@ -202,6 +205,12 @@ export class StoredCredentialProvider implements SynomemCredentialProvider {
|
|
|
202
205
|
private readonly store: CredentialStore,
|
|
203
206
|
private readonly env: NodeJS.ProcessEnv = process.env,
|
|
204
207
|
private readonly fetchImplementation: typeof fetch = fetch,
|
|
208
|
+
/**
|
|
209
|
+
* Where `synomem config`'s restricted-file credential store, if chosen,
|
|
210
|
+
* would have written an access key. Optional because local-only and
|
|
211
|
+
* environment-only callers have no such file to fall back to.
|
|
212
|
+
*/
|
|
213
|
+
private readonly home?: string,
|
|
205
214
|
) {}
|
|
206
215
|
|
|
207
216
|
async getAccessToken(signal?: AbortSignal): Promise<string | undefined> {
|
|
@@ -209,14 +218,20 @@ export class StoredCredentialProvider implements SynomemCredentialProvider {
|
|
|
209
218
|
if (!this.loaded) {
|
|
210
219
|
const stored = await this.store.get(this.reference);
|
|
211
220
|
/*
|
|
212
|
-
* An
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
* ignores it and lets the installation-key path handle it.
|
|
221
|
+
* An access key is not an OAuth credential: it cannot be refreshed and
|
|
222
|
+
* has no client or token endpoint. It is used exactly as stored,
|
|
223
|
+
* whichever of the two places it was found.
|
|
216
224
|
*/
|
|
217
|
-
|
|
225
|
+
if (stored && 'kind' in stored) {
|
|
226
|
+
this.staticAccessToken = stored.accessToken;
|
|
227
|
+
} else if (stored) {
|
|
228
|
+
this.credential = stored;
|
|
229
|
+
} else if (this.home) {
|
|
230
|
+
this.staticAccessToken = readCredentialFile(this.home);
|
|
231
|
+
}
|
|
218
232
|
this.loaded = true;
|
|
219
233
|
}
|
|
234
|
+
if (this.staticAccessToken) return this.staticAccessToken;
|
|
220
235
|
const credential = this.credential;
|
|
221
236
|
if (!credential) return undefined;
|
|
222
237
|
if (!credential.expiresAt || credential.expiresAt > Date.now()) return credential.accessToken;
|