document360-engine 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +10 -16
  2. package/README.md +1 -1
  3. package/dist/config.d.ts +20 -0
  4. package/dist/d360/tools.d.ts +15 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +28 -18
  7. package/dist/lib/writerMode.d.ts +18 -0
  8. package/dist/scope/inventory.d.ts +19 -0
  9. package/dist/session.d.ts +12 -1
  10. package/dist/sync/categoryMap.d.ts +39 -0
  11. package/dist/sync/docsRoot.d.ts +8 -0
  12. package/dist/sync/frontmatter.d.ts +10 -0
  13. package/dist/sync/hash.d.ts +7 -0
  14. package/dist/sync/index.d.ts +8 -0
  15. package/dist/sync/pull.d.ts +41 -0
  16. package/dist/sync/remote.d.ts +37 -0
  17. package/dist/sync/status.d.ts +27 -0
  18. package/dist/sync/types.d.ts +22 -0
  19. package/package.json +3 -3
  20. package/skills/CLAUDE.md +38 -2
  21. package/skills/analyze-codebase/SKILL.md +35 -17
  22. package/skills/d360-markdown/SKILL.md +99 -0
  23. package/skills/gap-analysis/SKILL.md +75 -0
  24. package/skills/publish-to-d360/SKILL.md +3 -2
  25. package/skills/write-article/SKILL.md +7 -0
  26. package/dist/config.js +0 -62
  27. package/dist/config.js.map +0 -1
  28. package/dist/d360/apiLog.js +0 -68
  29. package/dist/d360/apiLog.js.map +0 -1
  30. package/dist/d360/client.js +0 -192
  31. package/dist/d360/client.js.map +0 -1
  32. package/dist/d360/environments.js +0 -56
  33. package/dist/d360/environments.js.map +0 -1
  34. package/dist/d360/oauth.js +0 -162
  35. package/dist/d360/oauth.js.map +0 -1
  36. package/dist/d360/profile.js +0 -31
  37. package/dist/d360/profile.js.map +0 -1
  38. package/dist/d360/tokenStore.js +0 -50
  39. package/dist/d360/tokenStore.js.map +0 -1
  40. package/dist/d360/tools.js +0 -337
  41. package/dist/d360/tools.js.map +0 -1
  42. package/dist/d360/wire.js +0 -83
  43. package/dist/d360/wire.js.map +0 -1
  44. package/dist/index.js.map +0 -1
  45. package/dist/lib/auth.js +0 -25
  46. package/dist/lib/auth.js.map +0 -1
  47. package/dist/lib/messageQueue.js +0 -40
  48. package/dist/lib/messageQueue.js.map +0 -1
  49. package/dist/lib/paths.js +0 -35
  50. package/dist/lib/paths.js.map +0 -1
  51. package/dist/lib/sessionStore.js +0 -100
  52. package/dist/lib/sessionStore.js.map +0 -1
  53. package/dist/lib/suggestGen.js +0 -61
  54. package/dist/lib/suggestGen.js.map +0 -1
  55. package/dist/lib/titleGen.js +0 -64
  56. package/dist/lib/titleGen.js.map +0 -1
  57. package/dist/session.js +0 -220
  58. package/dist/session.js.map +0 -1
  59. package/skills/audit-docs/SKILL.md +0 -48
@@ -1,192 +0,0 @@
1
- import { refreshTokens, toStoredTokens } from './oauth.js';
2
- import { decodeJwtClaims, isExpired, loadTokens, saveTokens } from './tokenStore.js';
3
- import { logApiCall, logBodiesAlways, loggableBody } from './apiLog.js';
4
- export class D360AuthError extends Error {
5
- }
6
- export class D360ApiError extends Error {
7
- status;
8
- requestId;
9
- constructor(message, status, requestId) {
10
- super(message);
11
- this.status = status;
12
- this.requestId = requestId;
13
- }
14
- }
15
- /** Valid access token for the profile, refreshing if possible. Throws D360AuthError otherwise. */
16
- export async function getAccessToken(ctx) {
17
- const tokens = loadTokens(ctx.profile);
18
- if (!tokens) {
19
- throw new D360AuthError(`Not logged in to Document360 (profile "${ctx.profile}"). Run: d360-writer login --profile ${ctx.profile}`);
20
- }
21
- if (!isExpired(tokens))
22
- return tokens.accessToken;
23
- if (!tokens.refreshToken) {
24
- throw new D360AuthError(`Document360 session expired (profile "${ctx.profile}"). Run: d360-writer login --profile ${ctx.profile}`);
25
- }
26
- try {
27
- const refreshed = toStoredTokens(ctx.profile, await refreshTokens(ctx.connection, tokens.refreshToken));
28
- saveTokens(refreshed);
29
- return refreshed.accessToken;
30
- }
31
- catch (err) {
32
- throw new D360AuthError(`Document360 session expired and refresh failed (${err.message.slice(0, 120)}). Run: d360-writer login --profile ${ctx.profile}`);
33
- }
34
- }
35
- /** The project the writer acts on: explicit (profile/arg) wins, else the token's doc360_project_id claim. */
36
- export function resolveProjectId(ctx, configProjectId) {
37
- if (configProjectId)
38
- return configProjectId;
39
- const tokens = loadTokens(ctx.profile);
40
- const claims = tokens ? (decodeJwtClaims(tokens.accessToken) ?? {}) : {};
41
- const fromClaim = claims['doc360_project_id'];
42
- if (typeof fromClaim === 'string' && fromClaim)
43
- return fromClaim;
44
- throw new D360AuthError('No Document360 project resolved. Log in (the project is chosen during login) or set the profile\'s project.projectId in .d360-writer.json.');
45
- }
46
- async function rawFetch(ctx, method, path, opts = {}) {
47
- const token = await getAccessToken(ctx);
48
- const url = new URL(path.startsWith('http') ? path : `${ctx.connection.apiUrl}${path}`);
49
- for (const [k, v] of Object.entries(opts.query ?? {})) {
50
- if (v !== undefined)
51
- url.searchParams.set(k, String(v));
52
- }
53
- const requestBody = opts.body !== undefined ? JSON.stringify(opts.body) : undefined;
54
- const started = Date.now();
55
- const log = (extra) => logApiCall({
56
- ts: new Date().toISOString(),
57
- profile: ctx.profile,
58
- method,
59
- url: url.toString(),
60
- ms: Date.now() - started,
61
- ok: extra.ok,
62
- status: extra.status,
63
- requestId: extra.requestId,
64
- error: extra.error,
65
- ...(extra.withBodies ? { requestBody: loggableBody(requestBody), responseBody: loggableBody(extra.responseBody) } : {}),
66
- });
67
- let res;
68
- try {
69
- res = await fetch(url, {
70
- method,
71
- headers: {
72
- authorization: `Bearer ${token}`,
73
- accept: 'application/json',
74
- ...(requestBody !== undefined ? { 'content-type': 'application/json' } : {}),
75
- },
76
- body: requestBody,
77
- });
78
- }
79
- catch (err) {
80
- log({ ok: false, error: `network: ${err.message}`, withBodies: true });
81
- throw err;
82
- }
83
- const text = await res.text();
84
- let envelope = {};
85
- if (text) {
86
- try {
87
- envelope = JSON.parse(text);
88
- }
89
- catch {
90
- /* non-JSON body — handled below */
91
- }
92
- }
93
- if (!res.ok || envelope.success === false) {
94
- const detail = envelope.errors?.map(e => e.message ?? e.code).filter(Boolean).join('; ') || text.slice(0, 300) || res.statusText;
95
- log({ ok: false, status: res.status, requestId: envelope.request_id, error: detail, responseBody: text, withBodies: true });
96
- if (res.status === 401) {
97
- throw new D360AuthError(`Document360 rejected the token (401). Run: d360-writer login --profile ${ctx.profile}`);
98
- }
99
- // request_id makes the error support-ticket-ready (D360 can trace the rejection).
100
- const rid = envelope.request_id ? ` [request_id: ${envelope.request_id}]` : '';
101
- throw new D360ApiError(`Document360 API ${res.status}: ${detail}${rid}`, res.status, envelope.request_id);
102
- }
103
- log({ ok: true, status: res.status, requestId: envelope.request_id, responseBody: text, withBodies: logBodiesAlways() });
104
- return envelope;
105
- }
106
- /** Single request, returns the unwrapped `data`. */
107
- export async function d360Get(ctx, path, opts) {
108
- return (await rawFetch(ctx, 'GET', path, opts)).data;
109
- }
110
- export async function d360Post(ctx, path, opts) {
111
- return (await rawFetch(ctx, 'POST', path, opts)).data;
112
- }
113
- export async function d360Patch(ctx, path, opts) {
114
- return (await rawFetch(ctx, 'PATCH', path, opts)).data;
115
- }
116
- /** Multipart upload (Drive files). Does NOT set content-type — fetch derives the
117
- multipart boundary from the FormData. Returns the unwrapped `data`. */
118
- export async function d360Upload(ctx, path, form) {
119
- const token = await getAccessToken(ctx);
120
- const url = `${ctx.connection.apiUrl}${path}`;
121
- const started = Date.now();
122
- const log = (extra) => logApiCall({
123
- ts: new Date().toISOString(),
124
- profile: ctx.profile,
125
- method: 'POST',
126
- url,
127
- ms: Date.now() - started,
128
- ok: extra.ok,
129
- status: extra.status,
130
- requestId: extra.requestId,
131
- error: extra.error,
132
- ...(extra.withBodies ? { requestBody: '[multipart form-data]', responseBody: loggableBody(extra.responseBody) } : {}),
133
- });
134
- let res;
135
- try {
136
- res = await fetch(url, {
137
- method: 'POST',
138
- headers: { authorization: `Bearer ${token}`, accept: 'application/json' },
139
- body: form,
140
- });
141
- }
142
- catch (err) {
143
- log({ ok: false, error: `network: ${err.message}`, withBodies: true });
144
- throw err;
145
- }
146
- const text = await res.text();
147
- let envelope = {};
148
- if (text) {
149
- try {
150
- envelope = JSON.parse(text);
151
- }
152
- catch {
153
- /* non-JSON */
154
- }
155
- }
156
- if (!res.ok || envelope.success === false) {
157
- const detail = envelope.errors?.map(e => e.message ?? e.code).filter(Boolean).join('; ') || text.slice(0, 300) || res.statusText;
158
- log({ ok: false, status: res.status, requestId: envelope.request_id, error: detail, responseBody: text, withBodies: true });
159
- if (res.status === 401)
160
- throw new D360AuthError(`Document360 rejected the token (401). Run: d360-writer login --profile ${ctx.profile}`);
161
- const rid = envelope.request_id ? ` [request_id: ${envelope.request_id}]` : '';
162
- throw new D360ApiError(`Document360 upload ${res.status}: ${detail}${rid}`, res.status, envelope.request_id);
163
- }
164
- log({ ok: true, status: res.status, requestId: envelope.request_id, responseBody: text, withBodies: logBodiesAlways() });
165
- return envelope.data;
166
- }
167
- /** Cursor-paginated GET — follows pagination.next_cursor, concatenating data arrays. */
168
- export async function d360GetAll(ctx, path, opts = {}) {
169
- const out = [];
170
- let cursor;
171
- // Safety cap: 50 pages — a runaway pagination loop shouldn't hang the agent.
172
- for (let page = 0; page < 50; page++) {
173
- const envelope = await rawFetch(ctx, 'GET', path, { ...opts, query: { ...opts.query, cursor } });
174
- if (Array.isArray(envelope.data))
175
- out.push(...envelope.data);
176
- if (!envelope.pagination?.has_more || !envelope.pagination.next_cursor)
177
- break;
178
- cursor = envelope.pagination.next_cursor;
179
- }
180
- return out;
181
- }
182
- /** List the workspaces (project versions) in a project. Used by the workspace picker. */
183
- export async function listWorkspaces(ctx, projectId) {
184
- return d360GetAll(ctx, `/v3/projects/${projectId}/workspaces`);
185
- }
186
- /** Fetch one article with its markdown source. Used by the writer's /preview command. */
187
- export async function getArticle(ctx, projectId, articleId) {
188
- return d360Get(ctx, `/v3/projects/${projectId}/articles/${articleId}`, {
189
- query: { content_mode: 'raw' },
190
- });
191
- }
192
- //# sourceMappingURL=client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/d360/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMxE,MAAM,OAAO,aAAc,SAAQ,KAAK;CAAG;AAC3C,MAAM,OAAO,YAAa,SAAQ,KAAK;IAG1B;IACA;IAHX,YACE,OAAe,EACN,MAAc,EACd,SAAkB;QAE3B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHN,WAAM,GAAN,MAAM,CAAQ;QACd,cAAS,GAAT,SAAS,CAAS;IAG7B,CAAC;CACF;AAED,kGAAkG;AAClG,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAgB;IACnD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,aAAa,CAAC,0CAA0C,GAAG,CAAC,OAAO,wCAAwC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACtI,CAAC;IACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC,WAAW,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,MAAM,IAAI,aAAa,CAAC,yCAAyC,GAAG,CAAC,OAAO,wCAAwC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACrI,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACxG,UAAU,CAAC,SAAS,CAAC,CAAC;QACtB,OAAO,SAAS,CAAC,WAAW,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,aAAa,CACrB,mDAAoD,GAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,uCAAuC,GAAG,CAAC,OAAO,EAAE,CAC5I,CAAC;IACJ,CAAC;AACH,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,gBAAgB,CAAC,GAAgB,EAAE,eAAwB;IACzE,IAAI,eAAe;QAAE,OAAO,eAAe,CAAC;IAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,MAAM,SAAS,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC9C,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,IAAI,aAAa,CACrB,4IAA4I,CAC7I,CAAC;AACJ,CAAC;AAgBD,KAAK,UAAU,QAAQ,CAAI,GAAgB,EAAE,MAAc,EAAE,IAAY,EAAE,OAA2B,EAAE;IACtG,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;IACxF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC,KAAK,SAAS;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,CAAC,KAAuH,EAAE,EAAE,CACtI,UAAU,CAAC;QACT,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM;QACN,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;QACnB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;QACxB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,YAAY,CAAC,WAAW,CAAC,EAAE,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxH,CAAC,CAAC;IAEL,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACrB,MAAM;YACN,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,MAAM,EAAE,kBAAkB;gBAC1B,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7E;YACD,IAAI,EAAE,WAAW;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAa,GAAa,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,QAAQ,GAAgB,EAAE,CAAC;IAC/B,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgB,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC;QACjI,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5H,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,aAAa,CAAC,0EAA0E,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACnH,CAAC;QACD,kFAAkF;QAClF,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,YAAY,CAAC,mBAAmB,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,GAAG,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC5G,CAAC;IACD,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;IACzH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,oDAAoD;AACpD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAI,GAAgB,EAAE,IAAY,EAAE,IAAyB;IACxF,OAAO,CAAC,MAAM,QAAQ,CAAI,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAS,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,GAAgB,EAAE,IAAY,EAAE,IAAyB;IACzF,OAAO,CAAC,MAAM,QAAQ,CAAI,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAS,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,GAAgB,EAAE,IAAY,EAAE,IAAyB;IAC1F,OAAO,CAAC,MAAM,QAAQ,CAAI,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAS,CAAC;AACjE,CAAC;AAED;0EAC0E;AAC1E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAI,GAAgB,EAAE,IAAY,EAAE,IAAc;IAChF,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,CAAC,KAAuH,EAAE,EAAE,CACtI,UAAU,CAAC;QACT,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,MAAM;QACd,GAAG;QACH,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;QACxB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,uBAAuB,EAAE,YAAY,EAAE,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtH,CAAC,CAAC;IAEL,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACzE,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAa,GAAa,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,QAAQ,GAAgB,EAAE,CAAC;IAC/B,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgB,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC;QACjI,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5H,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,aAAa,CAAC,0EAA0E,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACzI,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,YAAY,CAAC,sBAAsB,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,GAAG,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC/G,CAAC;IACD,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;IACzH,OAAO,QAAQ,CAAC,IAAS,CAAC;AAC5B,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAI,GAAgB,EAAE,IAAY,EAAE,OAA2B,EAAE;IAC/F,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,IAAI,MAA0B,CAAC;IAC/B,6EAA6E;IAC7E,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAM,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACtG,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,WAAW;YAAE,MAAM;QAC9E,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,WAAW,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAUD,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAgB,EAAE,SAAiB;IACtE,OAAO,UAAU,CAAgB,GAAG,EAAE,gBAAgB,SAAS,aAAa,CAAC,CAAC;AAChF,CAAC;AAiBD,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAgB,EAAE,SAAiB,EAAE,SAAiB;IACrF,OAAO,OAAO,CAAc,GAAG,EAAE,gBAAgB,SAAS,aAAa,SAAS,EAAE,EAAE;QAClF,KAAK,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;KAC/B,CAAC,CAAC;AACL,CAAC"}
@@ -1,56 +0,0 @@
1
- const PRESETS = {
2
- berlin: {
3
- apiUrl: 'https://apihub.berlin.document360.net',
4
- portalUrl: 'https://portal.berlin.document360.net',
5
- authorizationUrl: 'https://identity.berlin.document360.net/connect/authorize',
6
- tokenUrl: 'https://identity.berlin.document360.net/connect/token',
7
- // Dedicated d360-writer client, confirmed working for Customer API V3 OAuth
8
- // on berlin (D360 API team, 2026-06-08).
9
- clientId: 'd360WriterAgentClient',
10
- // offline_access → refresh token (added to the client by the D360 API team 2026-06-08,
11
- // resolving the 1h-session limitation).
12
- scopes: ['openid', 'profile', 'email', 'customerApi', 'offline_access'],
13
- // Identity server shows the project chooser during login; token is project-scoped.
14
- acrValues: 'project_select',
15
- // RFC 8252 loopback — whitelisted for d360WriterAgentClient (D360 API team,
16
- // 2026-06-08). Port 3223 is fixed because the redirect URI must match the
17
- // registered value exactly. Override with D360_REDIRECT_URI only for testing.
18
- redirectUri: 'http://127.0.0.1:3223/callback',
19
- // Force a fresh login screen so a stale browser session/cached error page can't
20
- // hijack the flow (was forcing users into incognito). Override with D360_PROMPT.
21
- prompt: 'login',
22
- },
23
- // production: filled at Document360 OAuth GA (end of June 2026).
24
- };
25
- export function knownEnvironments() {
26
- return Object.keys(PRESETS);
27
- }
28
- export function resolveEnvironment(name = 'berlin') {
29
- return resolveConnection({ environment: name });
30
- }
31
- /**
32
- * Resolve a profile's connection into a concrete D360Environment. Layering, lowest→highest:
33
- * baked preset (named by `connection.environment`, default berlin) → inline profile fields →
34
- * D360_* env vars (testing escape hatch).
35
- */
36
- export function resolveConnection(connection) {
37
- const presetName = connection.environment ?? 'berlin';
38
- const preset = PRESETS[presetName];
39
- if (!preset) {
40
- throw new Error(`Unknown Document360 environment "${presetName}". Known: ${knownEnvironments().join(', ')}`);
41
- }
42
- const envScopes = process.env.D360_SCOPES?.split(/[\s,]+/).filter(Boolean);
43
- return {
44
- name: presetName,
45
- apiUrl: process.env.D360_API_URL ?? connection.apiUrl ?? preset.apiUrl,
46
- portalUrl: process.env.D360_PORTAL_URL ?? connection.portalUrl ?? preset.portalUrl,
47
- authorizationUrl: process.env.D360_AUTHORIZATION_URL ?? connection.authorizationUrl ?? preset.authorizationUrl,
48
- tokenUrl: process.env.D360_TOKEN_URL ?? connection.tokenUrl ?? preset.tokenUrl,
49
- clientId: process.env.D360_CLIENT_ID ?? connection.clientId ?? preset.clientId,
50
- scopes: envScopes ?? connection.scopes ?? preset.scopes,
51
- acrValues: process.env.D360_ACR_VALUES ?? connection.acrValues ?? preset.acrValues,
52
- redirectUri: process.env.D360_REDIRECT_URI ?? connection.redirectUri ?? preset.redirectUri,
53
- prompt: process.env.D360_PROMPT ?? connection.prompt ?? preset.prompt,
54
- };
55
- }
56
- //# sourceMappingURL=environments.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"environments.js","sourceRoot":"","sources":["../../src/d360/environments.ts"],"names":[],"mappings":"AAwBA,MAAM,OAAO,GAAkD;IAC7D,MAAM,EAAE;QACN,MAAM,EAAE,uCAAuC;QAC/C,SAAS,EAAE,uCAAuC;QAClD,gBAAgB,EAAE,2DAA2D;QAC7E,QAAQ,EAAE,uDAAuD;QACjE,4EAA4E;QAC5E,yCAAyC;QACzC,QAAQ,EAAE,uBAAuB;QACjC,uFAAuF;QACvF,wCAAwC;QACxC,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,gBAAgB,CAAC;QACvE,mFAAmF;QACnF,SAAS,EAAE,gBAAgB;QAC3B,4EAA4E;QAC5E,0EAA0E;QAC1E,8EAA8E;QAC9E,WAAW,EAAE,gCAAgC;QAC7C,gFAAgF;QAChF,iFAAiF;QACjF,MAAM,EAAE,OAAO;KAChB;IACD,iEAAiE;CAClE,CAAC;AAEF,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAI,GAAG,QAAQ;IAChD,OAAO,iBAAiB,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAA6B;IAC7D,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,IAAI,QAAQ,CAAC;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oCAAoC,UAAU,aAAa,iBAAiB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3E,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,UAAU,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;QACtE,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,UAAU,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS;QAClF,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU,CAAC,gBAAgB,IAAI,MAAM,CAAC,gBAAgB;QAC9G,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,UAAU,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;QAC9E,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,UAAU,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;QAC9E,MAAM,EAAE,SAAS,IAAI,UAAU,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;QACvD,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,UAAU,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS;QAClF,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,UAAU,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW;QAC1F,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,UAAU,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;KACtE,CAAC;AACJ,CAAC"}
@@ -1,162 +0,0 @@
1
- import { createHash, randomBytes } from 'node:crypto';
2
- import { createServer } from 'node:http';
3
- import { spawn } from 'node:child_process';
4
- const LOGIN_TIMEOUT_MS = 10 * 60 * 1000;
5
- function base64url(buf) {
6
- return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
7
- }
8
- export function buildAuthorizationUrl(env) {
9
- const verifier = base64url(randomBytes(32));
10
- const challenge = base64url(createHash('sha256').update(verifier).digest());
11
- const state = base64url(randomBytes(16));
12
- const url = new URL(env.authorizationUrl);
13
- url.searchParams.set('client_id', env.clientId);
14
- url.searchParams.set('response_type', 'code');
15
- url.searchParams.set('redirect_uri', env.redirectUri);
16
- url.searchParams.set('scope', env.scopes.join(' '));
17
- url.searchParams.set('state', state);
18
- url.searchParams.set('code_challenge', challenge);
19
- url.searchParams.set('code_challenge_method', 'S256');
20
- if (env.acrValues)
21
- url.searchParams.set('acr_values', env.acrValues);
22
- if (env.prompt)
23
- url.searchParams.set('prompt', env.prompt);
24
- return { url: url.toString(), verifier, state };
25
- }
26
- function openBrowser(url) {
27
- // D360_NO_BROWSER=1: print-only mode (SSH, CI, tests).
28
- if (process.env.D360_NO_BROWSER)
29
- return;
30
- const platform = process.platform;
31
- if (platform === 'win32') {
32
- // DO NOT use `cmd /c start` — cmd treats '&' in the URL as a command
33
- // separator and truncates the query string at the first '&' (dropping
34
- // redirect_uri → "Invalid redirect_uri"). PowerShell Start-Process with a
35
- // single-quoted URL passes the whole thing through verbatim.
36
- const safe = url.replace(/'/g, "''");
37
- spawn('powershell', ['-NoProfile', '-NonInteractive', '-Command', `Start-Process '${safe}'`], {
38
- detached: true,
39
- stdio: 'ignore',
40
- }).unref();
41
- }
42
- else if (platform === 'darwin') {
43
- spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
44
- }
45
- else {
46
- spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
47
- }
48
- }
49
- /** Wait for the OAuth redirect on the loopback address from redirectUri. */
50
- function waitForCallback(redirectUri, expectedState) {
51
- const target = new URL(redirectUri);
52
- let server;
53
- const result = new Promise((resolve, reject) => {
54
- const timer = setTimeout(() => {
55
- reject(new Error(`Timed out after ${LOGIN_TIMEOUT_MS / 60000} minutes waiting for the browser login.`));
56
- server.close();
57
- }, LOGIN_TIMEOUT_MS);
58
- server = createServer((req, res) => {
59
- const reqUrl = new URL(req.url ?? '/', `http://${target.host}`);
60
- if (reqUrl.pathname !== target.pathname) {
61
- res.writeHead(404).end();
62
- return;
63
- }
64
- const error = reqUrl.searchParams.get('error');
65
- const code = reqUrl.searchParams.get('code');
66
- const state = reqUrl.searchParams.get('state');
67
- const fail = (msg) => {
68
- res.writeHead(400, { 'content-type': 'text/html' });
69
- res.end(`<html><body><h3>Login failed</h3><p>${msg}</p><p>Return to the terminal.</p></body></html>`);
70
- clearTimeout(timer);
71
- reject(new Error(msg));
72
- server.close();
73
- };
74
- if (error)
75
- return fail(`${error}: ${reqUrl.searchParams.get('error_description') ?? ''}`);
76
- if (!code)
77
- return fail('No authorization code in the callback.');
78
- if (state !== expectedState)
79
- return fail('State mismatch — possible CSRF; try again.');
80
- res.writeHead(200, { 'content-type': 'text/html' });
81
- res.end('<html><body><h3>✓ Document360 login complete</h3><p>You can close this tab and return to the terminal.</p></body></html>');
82
- clearTimeout(timer);
83
- resolve(code);
84
- server.close();
85
- });
86
- server.on('error', err => {
87
- clearTimeout(timer);
88
- reject(new Error(`Could not listen on ${target.host} (${err.message}). ` +
89
- `Another process may hold the port — set D360_REDIRECT_URI to a free port and retry.`));
90
- });
91
- server.listen(Number(target.port) || 80, target.hostname);
92
- });
93
- return { server: server, result };
94
- }
95
- async function requestTokens(env, body) {
96
- const res = await fetch(env.tokenUrl, {
97
- method: 'POST',
98
- headers: { 'content-type': 'application/x-www-form-urlencoded' },
99
- body,
100
- });
101
- const text = await res.text();
102
- if (!res.ok) {
103
- throw new Error(`Token endpoint ${res.status}: ${text.slice(0, 400)}`);
104
- }
105
- return JSON.parse(text);
106
- }
107
- export async function exchangeCode(env, code, verifier) {
108
- return requestTokens(env, new URLSearchParams({
109
- grant_type: 'authorization_code',
110
- code,
111
- redirect_uri: env.redirectUri,
112
- client_id: env.clientId,
113
- code_verifier: verifier,
114
- }));
115
- }
116
- export async function refreshTokens(env, refreshToken) {
117
- return requestTokens(env, new URLSearchParams({
118
- grant_type: 'refresh_token',
119
- refresh_token: refreshToken,
120
- client_id: env.clientId,
121
- }));
122
- }
123
- export function toStoredTokens(profile, t) {
124
- const now = Date.now();
125
- return {
126
- profile,
127
- accessToken: t.access_token,
128
- refreshToken: t.refresh_token,
129
- idToken: t.id_token,
130
- scope: t.scope,
131
- obtainedAt: new Date(now).toISOString(),
132
- expiresAt: new Date(now + (t.expires_in ?? 3600) * 1000).toISOString(),
133
- };
134
- }
135
- /**
136
- * Interactive login. Default: loopback listener + browser. Manual mode: no
137
- * listener — the user pastes the full redirect URL (works even when the
138
- * registered redirect URI is not a loopback we can bind).
139
- */
140
- export async function loginPkce(env, opts, log) {
141
- const { url, verifier, state } = buildAuthorizationUrl(env);
142
- if (opts.manual) {
143
- log('Open this URL in a browser and sign in:');
144
- log(url);
145
- const pasted = await opts.promptForRedirect('Paste the full URL you were redirected to (it contains ?code=...):');
146
- const redirected = new URL(pasted.trim());
147
- const code = redirected.searchParams.get('code');
148
- const gotState = redirected.searchParams.get('state');
149
- if (!code)
150
- throw new Error('No code parameter found in the pasted URL.');
151
- if (gotState !== state)
152
- throw new Error('State mismatch in the pasted URL — restart the login.');
153
- return exchangeCode(env, code, verifier);
154
- }
155
- const { result } = waitForCallback(env.redirectUri, state);
156
- log('Opening your browser for Document360 sign-in…');
157
- log(`If it did not open, visit:\n ${url}`);
158
- openBrowser(url);
159
- const code = await result;
160
- return exchangeCode(env, code, verifier);
161
- }
162
- //# sourceMappingURL=oauth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/d360/oauth.ts"],"names":[],"mappings":"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"}
@@ -1,31 +0,0 @@
1
- import { readProjectConfig, resolveProfile, writeProjectConfig } from '../config.js';
2
- import { resolveConnection } from './environments.js';
3
- /**
4
- * Resolve the active profile:
5
- * - no `.d360-writer.json` at all → a bare berlin default (lets you `login` before `init`);
6
- * - config WITH `profiles` → resolve by name → defaultProfile;
7
- * - config WITHOUT `profiles` → ProfileConfigError (old shape; forces migration).
8
- */
9
- export function resolveActiveProfile(cwd, nameOverride) {
10
- const cfg = readProjectConfig(cwd);
11
- if (cfg === null) {
12
- const name = nameOverride ?? 'berlin';
13
- return { name, connection: resolveConnection({ environment: name }), project: {}, production: false };
14
- }
15
- const { name, profile } = resolveProfile(cfg, nameOverride);
16
- return {
17
- name,
18
- connection: resolveConnection(profile.connection),
19
- project: profile.project ?? {},
20
- production: profile.production === true,
21
- };
22
- }
23
- /** Persist a project id into a profile's `project` aspect (used by login auto-fill). */
24
- export function setProfileProject(cwd, profileName, project) {
25
- const cfg = readProjectConfig(cwd);
26
- if (!cfg?.profiles?.[profileName])
27
- return;
28
- cfg.profiles[profileName].project = { ...cfg.profiles[profileName].project, ...project };
29
- writeProjectConfig(cfg, cwd);
30
- }
31
- //# sourceMappingURL=profile.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/d360/profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,kBAAkB,EAA2C,MAAM,cAAc,CAAC;AAC9H,OAAO,EAAE,iBAAiB,EAAwB,MAAM,mBAAmB,CAAC;AAU5E;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW,EAAE,YAAqB;IACrE,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,YAAY,IAAI,QAAQ,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACxG,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC5D,OAAO;QACL,IAAI;QACJ,UAAU,EAAE,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC;QACjD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,UAAU,EAAE,OAAO,CAAC,UAAU,KAAK,IAAI;KACxC,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,WAAmB,EAAE,OAAuB;IACzF,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAyB,CAAC;IAC3D,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC;QAAE,OAAO;IAC1C,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IACzF,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC/B,CAAC"}
@@ -1,50 +0,0 @@
1
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { userDir, ensureDir } from '../lib/paths.js';
4
- function authDir() {
5
- return join(userDir(), 'auth');
6
- }
7
- function tokenPath(profile) {
8
- return join(authDir(), `${profile}.json`);
9
- }
10
- export function saveTokens(tokens) {
11
- ensureDir(authDir());
12
- writeFileSync(tokenPath(tokens.profile), JSON.stringify(tokens, null, 2));
13
- }
14
- export function loadTokens(profile) {
15
- const path = tokenPath(profile);
16
- if (!existsSync(path))
17
- return null;
18
- try {
19
- return JSON.parse(readFileSync(path, 'utf8'));
20
- }
21
- catch {
22
- return null;
23
- }
24
- }
25
- export function clearTokens(profile) {
26
- const path = tokenPath(profile);
27
- if (!existsSync(path))
28
- return false;
29
- unlinkSync(path);
30
- return true;
31
- }
32
- export function isExpired(tokens, skewSeconds = 60) {
33
- return Date.now() >= new Date(tokens.expiresAt).getTime() - skewSeconds * 1000;
34
- }
35
- /** Decode a JWT's payload without verification (for display/claims discovery only). */
36
- export function decodeJwtClaims(token) {
37
- if (!token)
38
- return null;
39
- const parts = token.split('.');
40
- if (parts.length !== 3)
41
- return null; // opaque token
42
- try {
43
- const payload = Buffer.from(parts[1].replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8');
44
- return JSON.parse(payload);
45
- }
46
- catch {
47
- return null;
48
- }
49
- }
50
- //# sourceMappingURL=tokenStore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokenStore.js","sourceRoot":"","sources":["../../src/d360/tokenStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAcrD,SAAS,OAAO;IACd,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;IACrB,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAiB,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,UAAU,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAoB,EAAE,WAAW,GAAG,EAAE;IAC9D,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,WAAW,GAAG,IAAI,CAAC;AACjF,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAAC,KAAyB;IACvD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,eAAe;IACpD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACxG,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}