@workjournal/shared 0.1.0
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 +19 -0
- package/dist/constants.d.ts +55 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +45 -0
- package/dist/constants.js.map +1 -0
- package/dist/credentials.d.ts +30 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +125 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/opaque-token.d.ts +49 -0
- package/dist/opaque-token.d.ts.map +1 -0
- package/dist/opaque-token.js +108 -0
- package/dist/opaque-token.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @workjournal/shared
|
|
2
|
+
|
|
3
|
+
Shared types, constants, and credential helpers used by [@workjournal/cli](https://www.npmjs.com/package/@workjournal/cli) and [@workjournal/mcp-server](https://www.npmjs.com/package/@workjournal/mcp-server).
|
|
4
|
+
|
|
5
|
+
This package isn't intended for direct consumption — it's a workspace dependency of the published Workjournal client packages. It's published to npm only so that those packages can resolve their own dependencies.
|
|
6
|
+
|
|
7
|
+
## Exports
|
|
8
|
+
|
|
9
|
+
| Subpath | Contents |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `@workjournal/shared` | Types (`Entry`, `Journal`, `JournalMember`, `Invitation`, …), API path builders, error codes, opaque-token codec |
|
|
12
|
+
| `@workjournal/shared/credentials` | Node-only credential file I/O + `/v1/auth/refresh` client (used by CLI + MCP server) |
|
|
13
|
+
|
|
14
|
+
The default entry has zero runtime dependencies and works in any JavaScript runtime (Node, Cloudflare Workers, browsers). The `credentials` subpath imports `node:fs` / `node:os` and is Node-only.
|
|
15
|
+
|
|
16
|
+
## Links
|
|
17
|
+
|
|
18
|
+
- [Workjournal](https://workjournal.pro)
|
|
19
|
+
- [GitHub](https://github.com/workjournal-pro/workjournal)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare const API_VERSION: "v1";
|
|
2
|
+
export declare const TIER_LIMITS: {
|
|
3
|
+
readonly PERSONAL: {
|
|
4
|
+
readonly journals: 5;
|
|
5
|
+
readonly entriesPerJournal: 500;
|
|
6
|
+
};
|
|
7
|
+
readonly PRO: {
|
|
8
|
+
readonly journals: 20;
|
|
9
|
+
readonly entriesPerJournal: 2000;
|
|
10
|
+
};
|
|
11
|
+
readonly ADMIN: {
|
|
12
|
+
readonly journals: 100;
|
|
13
|
+
readonly entriesPerJournal: 10000;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare const API_PATHS: {
|
|
17
|
+
readonly health: "/v1/health";
|
|
18
|
+
readonly accounts: "/v1/accounts";
|
|
19
|
+
readonly account: (id: string) => string;
|
|
20
|
+
readonly journals: "/v1/journals";
|
|
21
|
+
readonly journal: (id: string) => string;
|
|
22
|
+
readonly entries: (journalId: string) => string;
|
|
23
|
+
readonly entry: (journalId: string, index: number | string) => string;
|
|
24
|
+
readonly searchEntries: (journalId: string) => string;
|
|
25
|
+
readonly members: (journalId: string) => string;
|
|
26
|
+
readonly member: (journalId: string, userId: string) => string;
|
|
27
|
+
readonly invitations: (journalId: string) => string;
|
|
28
|
+
readonly invitation: (journalId: string, invitationId: string) => string;
|
|
29
|
+
readonly acceptInvitation: "/v1/invitations/accept";
|
|
30
|
+
readonly exportJournal: (journalId: string) => string;
|
|
31
|
+
readonly publicJournal: (slug: string) => string;
|
|
32
|
+
readonly publicEntries: (slug: string) => string;
|
|
33
|
+
};
|
|
34
|
+
export declare const ERROR_CODES: {
|
|
35
|
+
readonly BAD_REQUEST: "BAD_REQUEST";
|
|
36
|
+
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
37
|
+
readonly FORBIDDEN: "FORBIDDEN";
|
|
38
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
39
|
+
readonly CONFLICT: "CONFLICT";
|
|
40
|
+
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
41
|
+
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
42
|
+
readonly EMAIL_MISMATCH: "EMAIL_MISMATCH";
|
|
43
|
+
readonly INVITATION_EXPIRED: "INVITATION_EXPIRED";
|
|
44
|
+
readonly INVITATION_REVOKED: "INVITATION_REVOKED";
|
|
45
|
+
readonly INVITATION_ALREADY_ACCEPTED: "INVITATION_ALREADY_ACCEPTED";
|
|
46
|
+
readonly TIER_LIMIT_REACHED: "TIER_LIMIT_REACHED";
|
|
47
|
+
};
|
|
48
|
+
export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
|
49
|
+
export declare const MAX_SUMMARY_LENGTH = 500;
|
|
50
|
+
export declare const MAX_JOURNAL_NAME_LENGTH = 255;
|
|
51
|
+
export declare const MAX_EMAIL_LENGTH = 320;
|
|
52
|
+
export declare const DEFAULT_PAGE_LIMIT = 50;
|
|
53
|
+
export declare const MAX_PAGE_LIMIT = 100;
|
|
54
|
+
export declare const PUBLIC_SLUG_LENGTH = 12;
|
|
55
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,EAAG,IAAa,CAAC;AAEzC,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAId,CAAC;AAEX,eAAO,MAAM,SAAS;;;2BAGP,MAAM;;2BAEN,MAAM;kCACC,MAAM;gCACR,MAAM,SAAS,MAAM,GAAG,MAAM;wCAEtB,MAAM;kCACZ,MAAM;iCACP,MAAM,UAAU,MAAM;sCAEjB,MAAM;qCACP,MAAM,gBAAgB,MAAM;;wCAGzB,MAAM;mCACX,MAAM;mCACN,MAAM;CACnB,CAAC;AAEX,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAad,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEvE,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,eAAO,MAAM,kBAAkB,KAAK,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const API_VERSION = 'v1';
|
|
2
|
+
export const TIER_LIMITS = {
|
|
3
|
+
PERSONAL: { journals: 5, entriesPerJournal: 500 },
|
|
4
|
+
PRO: { journals: 20, entriesPerJournal: 2000 },
|
|
5
|
+
ADMIN: { journals: 100, entriesPerJournal: 10000 },
|
|
6
|
+
};
|
|
7
|
+
export const API_PATHS = {
|
|
8
|
+
health: `/${API_VERSION}/health`,
|
|
9
|
+
accounts: `/${API_VERSION}/accounts`,
|
|
10
|
+
account: (id) => `/${API_VERSION}/accounts/${id}`,
|
|
11
|
+
journals: `/${API_VERSION}/journals`,
|
|
12
|
+
journal: (id) => `/${API_VERSION}/journals/${id}`,
|
|
13
|
+
entries: (journalId) => `/${API_VERSION}/journals/${journalId}/entries`,
|
|
14
|
+
entry: (journalId, index) => `/${API_VERSION}/journals/${encodeURIComponent(journalId)}/entries/${encodeURIComponent(String(index))}`,
|
|
15
|
+
searchEntries: (journalId) => `/${API_VERSION}/journals/${journalId}/entries/search`,
|
|
16
|
+
members: (journalId) => `/${API_VERSION}/journals/${journalId}/members`,
|
|
17
|
+
member: (journalId, userId) => `/${API_VERSION}/journals/${journalId}/members/${userId}`,
|
|
18
|
+
invitations: (journalId) => `/${API_VERSION}/journals/${journalId}/invitations`,
|
|
19
|
+
invitation: (journalId, invitationId) => `/${API_VERSION}/journals/${journalId}/invitations/${invitationId}`,
|
|
20
|
+
acceptInvitation: `/${API_VERSION}/invitations/accept`,
|
|
21
|
+
exportJournal: (journalId) => `/${API_VERSION}/journals/${journalId}/export`,
|
|
22
|
+
publicJournal: (slug) => `/${API_VERSION}/public/${slug}`,
|
|
23
|
+
publicEntries: (slug) => `/${API_VERSION}/public/${slug}/entries`,
|
|
24
|
+
};
|
|
25
|
+
export const ERROR_CODES = {
|
|
26
|
+
BAD_REQUEST: 'BAD_REQUEST',
|
|
27
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
28
|
+
FORBIDDEN: 'FORBIDDEN',
|
|
29
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
30
|
+
CONFLICT: 'CONFLICT',
|
|
31
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
32
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
33
|
+
EMAIL_MISMATCH: 'EMAIL_MISMATCH',
|
|
34
|
+
INVITATION_EXPIRED: 'INVITATION_EXPIRED',
|
|
35
|
+
INVITATION_REVOKED: 'INVITATION_REVOKED',
|
|
36
|
+
INVITATION_ALREADY_ACCEPTED: 'INVITATION_ALREADY_ACCEPTED',
|
|
37
|
+
TIER_LIMIT_REACHED: 'TIER_LIMIT_REACHED',
|
|
38
|
+
};
|
|
39
|
+
export const MAX_SUMMARY_LENGTH = 500;
|
|
40
|
+
export const MAX_JOURNAL_NAME_LENGTH = 255;
|
|
41
|
+
export const MAX_EMAIL_LENGTH = 320;
|
|
42
|
+
export const DEFAULT_PAGE_LIMIT = 50;
|
|
43
|
+
export const MAX_PAGE_LIMIT = 100;
|
|
44
|
+
export const PUBLIC_SLUG_LENGTH = 12;
|
|
45
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,IAAa,CAAC;AAEzC,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,iBAAiB,EAAE,GAAG,EAAE;IACjD,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE;IAC9C,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE;CACzC,CAAC;AAEX,MAAM,CAAC,MAAM,SAAS,GAAG;IACxB,MAAM,EAAE,IAAI,WAAW,SAAS;IAChC,QAAQ,EAAE,IAAI,WAAW,WAAW;IACpC,OAAO,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,EAAE,EAAE;IACzD,QAAQ,EAAE,IAAI,WAAW,WAAW;IACpC,OAAO,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,EAAE,EAAE;IACzD,OAAO,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,SAAS,UAAU;IAC/E,KAAK,EAAE,CAAC,SAAiB,EAAE,KAAsB,EAAE,EAAE,CACpD,IAAI,WAAW,aAAa,kBAAkB,CAAC,SAAS,CAAC,YAAY,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;IACzG,aAAa,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,SAAS,iBAAiB;IAC5F,OAAO,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,SAAS,UAAU;IAC/E,MAAM,EAAE,CAAC,SAAiB,EAAE,MAAc,EAAE,EAAE,CAC7C,IAAI,WAAW,aAAa,SAAS,YAAY,MAAM,EAAE;IAC1D,WAAW,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,SAAS,cAAc;IACvF,UAAU,EAAE,CAAC,SAAiB,EAAE,YAAoB,EAAE,EAAE,CACvD,IAAI,WAAW,aAAa,SAAS,gBAAgB,YAAY,EAAE;IACpE,gBAAgB,EAAE,IAAI,WAAW,qBAAqB;IACtD,aAAa,EAAE,CAAC,SAAiB,EAAE,EAAE,CAAC,IAAI,WAAW,aAAa,SAAS,SAAS;IACpF,aAAa,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,WAAW,WAAW,IAAI,EAAE;IACjE,aAAa,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,WAAW,WAAW,IAAI,UAAU;CAChE,CAAC;AAEX,MAAM,CAAC,MAAM,WAAW,GAAG;IAC1B,WAAW,EAAE,aAAa;IAC1B,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,gBAAgB,EAAE,kBAAkB;IACpC,cAAc,EAAE,gBAAgB;IAChC,cAAc,EAAE,gBAAgB;IAChC,kBAAkB,EAAE,oBAAoB;IACxC,kBAAkB,EAAE,oBAAoB;IACxC,2BAA2B,EAAE,6BAA6B;IAC1D,kBAAkB,EAAE,oBAAoB;CAC/B,CAAC;AAIX,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAEpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AACrC,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAElC,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface StoredCredentials {
|
|
2
|
+
access_token: string;
|
|
3
|
+
refresh_token?: string;
|
|
4
|
+
expires_at: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const CONFIG_DIR: string;
|
|
7
|
+
export interface LoginState {
|
|
8
|
+
verifier: string;
|
|
9
|
+
challenge: string;
|
|
10
|
+
created_at: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function readCredentials(): StoredCredentials | null;
|
|
13
|
+
export declare function writeCredentials(creds: StoredCredentials): void;
|
|
14
|
+
export declare function clearCredentials(): void;
|
|
15
|
+
export declare function writeLoginState(state: LoginState): void;
|
|
16
|
+
/**
|
|
17
|
+
* Read the in-progress login state file. Returns null if missing or unreadable.
|
|
18
|
+
* Does NOT enforce TTL — callers should check `created_at` against `LOGIN_STATE_TTL_MS`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readLoginState(): LoginState | null;
|
|
21
|
+
export declare function clearLoginState(): void;
|
|
22
|
+
export declare function isLoginStateExpired(state: LoginState): boolean;
|
|
23
|
+
export declare function isExpired(creds: StoredCredentials): boolean;
|
|
24
|
+
export declare function refreshAccessToken(refreshToken: string): Promise<StoredCredentials>;
|
|
25
|
+
/**
|
|
26
|
+
* Get a valid access token, refreshing if expired.
|
|
27
|
+
* Returns null if no credentials are stored.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getAccessToken(): Promise<string | null>;
|
|
30
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,iBAAiB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,UAAU,QAA2E,CAAC;AAOnG,MAAM,WAAW,UAAU;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACnB;AAQD,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAU1D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAI/D;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAIvC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAIvD;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CA0BlD;AAED,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAI9D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAE3D;AAID,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0BzF;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiB7D"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
export const CONFIG_DIR = process.env['WORKJOURNAL_CONFIG_DIR'] ?? join(homedir(), '.workjournal');
|
|
5
|
+
const CREDENTIALS_PATH = join(CONFIG_DIR, 'credentials.json');
|
|
6
|
+
const CREDENTIALS_TMP_PATH = `${CREDENTIALS_PATH}.tmp`;
|
|
7
|
+
const LOGIN_STATE_PATH = join(CONFIG_DIR, 'cli-login-state.json');
|
|
8
|
+
const LOGIN_STATE_TMP_PATH = `${LOGIN_STATE_PATH}.tmp`;
|
|
9
|
+
const LOGIN_STATE_TTL_MS = 10 * 60 * 1000;
|
|
10
|
+
function ensureConfigDir() {
|
|
11
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
12
|
+
mkdirSync(CONFIG_DIR, { mode: 0o700, recursive: true });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function readCredentials() {
|
|
16
|
+
if (!existsSync(CREDENTIALS_PATH)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const raw = readFileSync(CREDENTIALS_PATH, 'utf-8');
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function writeCredentials(creds) {
|
|
28
|
+
ensureConfigDir();
|
|
29
|
+
writeFileSync(CREDENTIALS_TMP_PATH, `${JSON.stringify(creds, null, '\t')}\n`, { mode: 0o600 });
|
|
30
|
+
renameSync(CREDENTIALS_TMP_PATH, CREDENTIALS_PATH);
|
|
31
|
+
}
|
|
32
|
+
export function clearCredentials() {
|
|
33
|
+
if (existsSync(CREDENTIALS_PATH)) {
|
|
34
|
+
unlinkSync(CREDENTIALS_PATH);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function writeLoginState(state) {
|
|
38
|
+
ensureConfigDir();
|
|
39
|
+
writeFileSync(LOGIN_STATE_TMP_PATH, `${JSON.stringify(state, null, '\t')}\n`, { mode: 0o600 });
|
|
40
|
+
renameSync(LOGIN_STATE_TMP_PATH, LOGIN_STATE_PATH);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Read the in-progress login state file. Returns null if missing or unreadable.
|
|
44
|
+
* Does NOT enforce TTL — callers should check `created_at` against `LOGIN_STATE_TTL_MS`.
|
|
45
|
+
*/
|
|
46
|
+
export function readLoginState() {
|
|
47
|
+
if (!existsSync(LOGIN_STATE_PATH)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const raw = readFileSync(LOGIN_STATE_PATH, 'utf-8');
|
|
52
|
+
const parsed = JSON.parse(raw);
|
|
53
|
+
if (!parsed ||
|
|
54
|
+
typeof parsed !== 'object' ||
|
|
55
|
+
typeof parsed.verifier !== 'string' ||
|
|
56
|
+
parsed.verifier.length === 0 ||
|
|
57
|
+
typeof parsed.challenge !== 'string' ||
|
|
58
|
+
parsed.challenge.length === 0 ||
|
|
59
|
+
typeof parsed.created_at !== 'string') {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
verifier: parsed.verifier,
|
|
64
|
+
challenge: parsed.challenge,
|
|
65
|
+
created_at: parsed.created_at,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function clearLoginState() {
|
|
73
|
+
if (existsSync(LOGIN_STATE_PATH)) {
|
|
74
|
+
unlinkSync(LOGIN_STATE_PATH);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function isLoginStateExpired(state) {
|
|
78
|
+
const created = Date.parse(state.created_at);
|
|
79
|
+
if (!Number.isFinite(created))
|
|
80
|
+
return true;
|
|
81
|
+
return Date.now() - created > LOGIN_STATE_TTL_MS;
|
|
82
|
+
}
|
|
83
|
+
export function isExpired(creds) {
|
|
84
|
+
return new Date(creds.expires_at) < new Date();
|
|
85
|
+
}
|
|
86
|
+
const API_URL = process.env['WORKJOURNAL_API_URL'] ?? 'https://api.workjournal.pro';
|
|
87
|
+
export async function refreshAccessToken(refreshToken) {
|
|
88
|
+
const res = await fetch(`${API_URL}/v1/auth/refresh`, {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
headers: { 'Content-Type': 'application/json' },
|
|
91
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
92
|
+
});
|
|
93
|
+
if (!res.ok) {
|
|
94
|
+
const text = await res.text();
|
|
95
|
+
throw new Error(`Token refresh failed (${res.status}): ${text}`);
|
|
96
|
+
}
|
|
97
|
+
const data = (await res.json());
|
|
98
|
+
const expiresAt = new Date(Date.now() + data.expires_in * 1000).toISOString();
|
|
99
|
+
const creds = {
|
|
100
|
+
access_token: data.access_token,
|
|
101
|
+
refresh_token: data.refresh_token,
|
|
102
|
+
expires_at: expiresAt,
|
|
103
|
+
};
|
|
104
|
+
writeCredentials(creds);
|
|
105
|
+
return creds;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get a valid access token, refreshing if expired.
|
|
109
|
+
* Returns null if no credentials are stored.
|
|
110
|
+
*/
|
|
111
|
+
export async function getAccessToken() {
|
|
112
|
+
const creds = readCredentials();
|
|
113
|
+
if (!creds) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
if (isExpired(creds)) {
|
|
117
|
+
if (!creds.refresh_token) {
|
|
118
|
+
throw new Error('Access token expired and no refresh token available. Please run `workjournal login` again.');
|
|
119
|
+
}
|
|
120
|
+
const refreshed = await refreshAccessToken(creds.refresh_token);
|
|
121
|
+
return refreshed.access_token;
|
|
122
|
+
}
|
|
123
|
+
return creds.access_token;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { ErrorCode } from './constants.js';
|
|
2
|
+
export { API_PATHS, API_VERSION, DEFAULT_PAGE_LIMIT, ERROR_CODES, MAX_EMAIL_LENGTH, MAX_JOURNAL_NAME_LENGTH, MAX_PAGE_LIMIT, MAX_SUMMARY_LENGTH, TIER_LIMITS, } from './constants.js';
|
|
3
|
+
export type { BearerResolution, WrappedPayload } from './opaque-token.js';
|
|
4
|
+
export { AAD_STRING, isOpaqueToken, KEY_LEN, NONCE_LEN, resolveBearer, TAG_LEN, unwrapToken, WJTK_PREFIX, wrapToken, } from './opaque-token.js';
|
|
5
|
+
export type { AcceptInvitationRequest, Account, AccountType, ApiError, CreateAccountRequest, CreateEntryRequest, CreateInvitationRequest, CreateJournalRequest, Entry, EntrySummary, Invitation, Journal, JournalMember, PaginatedResponse, UpdateEntryRequest, UpdateJournalRequest, } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EACN,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,WAAW,GACX,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EACN,UAAU,EACV,aAAa,EACb,OAAO,EACP,SAAS,EACT,aAAa,EACb,OAAO,EACP,WAAW,EACX,WAAW,EACX,SAAS,GACT,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACX,uBAAuB,EACvB,OAAO,EACP,WAAW,EACX,QAAQ,EACR,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,EACL,YAAY,EACZ,UAAU,EACV,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,GACpB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { API_PATHS, API_VERSION, DEFAULT_PAGE_LIMIT, ERROR_CODES, MAX_EMAIL_LENGTH, MAX_JOURNAL_NAME_LENGTH, MAX_PAGE_LIMIT, MAX_SUMMARY_LENGTH, TIER_LIMITS, } from './constants.js';
|
|
2
|
+
export { AAD_STRING, isOpaqueToken, KEY_LEN, NONCE_LEN, resolveBearer, TAG_LEN, unwrapToken, WJTK_PREFIX, wrapToken, } from './opaque-token.js';
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,kBAAkB,EAClB,WAAW,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACN,UAAU,EACV,aAAa,EACb,OAAO,EACP,SAAS,EACT,aAAa,EACb,OAAO,EACP,WAAW,EACX,WAAW,EACX,SAAS,GACT,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AEAD-wrapped opaque access tokens.
|
|
3
|
+
*
|
|
4
|
+
* Shared between `apps/auth-proxy` (which wraps Supabase JWTs as `wjtk_` tokens
|
|
5
|
+
* at `/oauth/token`) and `apps/api` (which unwraps on every request before
|
|
6
|
+
* handing the inner JWT to `supabase-js`). Keeping the wire format in one file
|
|
7
|
+
* prevents drift between the two sides — a mismatch in AAD, nonce length, or
|
|
8
|
+
* payload shape silently breaks every MCP-issued session.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WJTK_PREFIX = "wjtk_";
|
|
11
|
+
export declare const AAD_STRING = "workjournal:v1";
|
|
12
|
+
export declare const NONCE_LEN = 12;
|
|
13
|
+
export declare const TAG_LEN = 16;
|
|
14
|
+
export declare const KEY_LEN = 32;
|
|
15
|
+
export interface WrappedPayload {
|
|
16
|
+
/** Inner Supabase-signed JWT. */
|
|
17
|
+
j: string;
|
|
18
|
+
/** Unix expiry seconds — mirrors the inner JWT's exp. */
|
|
19
|
+
e: number;
|
|
20
|
+
/** Optional OAuth client_id. */
|
|
21
|
+
c?: string;
|
|
22
|
+
/** Wire-format version. */
|
|
23
|
+
v: 1;
|
|
24
|
+
}
|
|
25
|
+
export declare function isOpaqueToken(token: string | undefined | null): token is string;
|
|
26
|
+
export declare function wrapToken(innerJwt: string, exp: number, clientId: string | undefined, keyB64url: string): Promise<string>;
|
|
27
|
+
export declare function unwrapToken(opaque: string, keyB64url: string): Promise<WrappedPayload | null>;
|
|
28
|
+
/**
|
|
29
|
+
* Result discriminant for `resolveBearer`:
|
|
30
|
+
* - `passthrough` — token was not a `wjtk_` wrapper; caller should use it as-is
|
|
31
|
+
* (web-app Supabase JWT path).
|
|
32
|
+
* - `unwrapped` — valid wrapper; `.jwt` is the inner Supabase JWT.
|
|
33
|
+
* - `invalid` — wrapper was tampered, expired, or encrypted with a different
|
|
34
|
+
* key. Callers MUST NOT treat this as equivalent to a missing header — it's
|
|
35
|
+
* an explicit authentication failure.
|
|
36
|
+
*/
|
|
37
|
+
export type BearerResolution = {
|
|
38
|
+
kind: 'passthrough';
|
|
39
|
+
jwt: string;
|
|
40
|
+
} | {
|
|
41
|
+
kind: 'unwrapped';
|
|
42
|
+
jwt: string;
|
|
43
|
+
payload: WrappedPayload;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'invalid';
|
|
46
|
+
reason: 'tampered' | 'expired';
|
|
47
|
+
};
|
|
48
|
+
export declare function resolveBearer(token: string, keyB64url: string): Promise<BearerResolution>;
|
|
49
|
+
//# sourceMappingURL=opaque-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opaque-token.d.ts","sourceRoot":"","sources":["../src/opaque-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,UAAU,mBAAmB,CAAC;AAC3C,eAAO,MAAM,SAAS,KAAK,CAAC;AAC5B,eAAO,MAAM,OAAO,KAAK,CAAC;AAC1B,eAAO,MAAM,OAAO,KAAK,CAAC;AAI1B,MAAM,WAAW,cAAc;IAC9B,iCAAiC;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;IACV,gCAAgC;IAChC,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,CAAC,EAAE,CAAC,CAAC;CACL;AA0BD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,IAAI,MAAM,CAE/E;AAED,wBAAsB,SAAS,CAC9B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,WAAW,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA2ChC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GACzB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAAA;CAAE,CAAC;AAEvD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAM/F"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AEAD-wrapped opaque access tokens.
|
|
3
|
+
*
|
|
4
|
+
* Shared between `apps/auth-proxy` (which wraps Supabase JWTs as `wjtk_` tokens
|
|
5
|
+
* at `/oauth/token`) and `apps/api` (which unwraps on every request before
|
|
6
|
+
* handing the inner JWT to `supabase-js`). Keeping the wire format in one file
|
|
7
|
+
* prevents drift between the two sides — a mismatch in AAD, nonce length, or
|
|
8
|
+
* payload shape silently breaks every MCP-issued session.
|
|
9
|
+
*/
|
|
10
|
+
export const WJTK_PREFIX = 'wjtk_';
|
|
11
|
+
export const AAD_STRING = 'workjournal:v1';
|
|
12
|
+
export const NONCE_LEN = 12;
|
|
13
|
+
export const TAG_LEN = 16;
|
|
14
|
+
export const KEY_LEN = 32;
|
|
15
|
+
const AAD = new TextEncoder().encode(AAD_STRING);
|
|
16
|
+
function base64urlEncode(bytes) {
|
|
17
|
+
let binary = '';
|
|
18
|
+
for (const byte of bytes)
|
|
19
|
+
binary += String.fromCharCode(byte);
|
|
20
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
21
|
+
}
|
|
22
|
+
function base64urlDecode(s) {
|
|
23
|
+
const padded = s.replace(/-/g, '+').replace(/_/g, '/') + '==='.slice((s.length + 3) % 4);
|
|
24
|
+
const binary = atob(padded);
|
|
25
|
+
const bytes = new Uint8Array(binary.length);
|
|
26
|
+
for (let i = 0; i < binary.length; i++) {
|
|
27
|
+
bytes[i] = binary.charCodeAt(i);
|
|
28
|
+
}
|
|
29
|
+
return bytes;
|
|
30
|
+
}
|
|
31
|
+
async function importKey(keyB64url, usages) {
|
|
32
|
+
const keyBytes = base64urlDecode(keyB64url);
|
|
33
|
+
if (keyBytes.length !== KEY_LEN) {
|
|
34
|
+
throw new Error(`TOKEN_ENC_KEY must be ${KEY_LEN} bytes`);
|
|
35
|
+
}
|
|
36
|
+
return crypto.subtle.importKey('raw', keyBytes, 'AES-GCM', false, usages);
|
|
37
|
+
}
|
|
38
|
+
export function isOpaqueToken(token) {
|
|
39
|
+
return typeof token === 'string' && token.startsWith(WJTK_PREFIX);
|
|
40
|
+
}
|
|
41
|
+
export async function wrapToken(innerJwt, exp, clientId, keyB64url) {
|
|
42
|
+
const key = await importKey(keyB64url, ['encrypt']);
|
|
43
|
+
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_LEN));
|
|
44
|
+
const payload = { j: innerJwt, e: exp, v: 1 };
|
|
45
|
+
if (clientId)
|
|
46
|
+
payload.c = clientId;
|
|
47
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(payload));
|
|
48
|
+
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: 'AES-GCM', iv: nonce, additionalData: AAD }, key, plaintext));
|
|
49
|
+
const combined = new Uint8Array(NONCE_LEN + ciphertext.byteLength);
|
|
50
|
+
combined.set(nonce, 0);
|
|
51
|
+
combined.set(ciphertext, NONCE_LEN);
|
|
52
|
+
return WJTK_PREFIX + base64urlEncode(combined);
|
|
53
|
+
}
|
|
54
|
+
export async function unwrapToken(opaque, keyB64url) {
|
|
55
|
+
if (!opaque.startsWith(WJTK_PREFIX))
|
|
56
|
+
return null;
|
|
57
|
+
let combined;
|
|
58
|
+
try {
|
|
59
|
+
combined = base64urlDecode(opaque.slice(WJTK_PREFIX.length));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (combined.length < NONCE_LEN + TAG_LEN)
|
|
65
|
+
return null;
|
|
66
|
+
const nonce = combined.slice(0, NONCE_LEN);
|
|
67
|
+
const ciphertext = combined.slice(NONCE_LEN);
|
|
68
|
+
let key;
|
|
69
|
+
try {
|
|
70
|
+
key = await importKey(keyB64url, ['decrypt']);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
let plaintext;
|
|
76
|
+
try {
|
|
77
|
+
plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: nonce, additionalData: AAD }, key, ciphertext);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
let payload;
|
|
83
|
+
try {
|
|
84
|
+
payload = JSON.parse(new TextDecoder().decode(plaintext));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
if (typeof payload !== 'object' ||
|
|
90
|
+
payload === null ||
|
|
91
|
+
typeof payload.j !== 'string' ||
|
|
92
|
+
typeof payload.e !== 'number' ||
|
|
93
|
+
payload.v !== 1) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return payload;
|
|
97
|
+
}
|
|
98
|
+
export async function resolveBearer(token, keyB64url) {
|
|
99
|
+
if (!isOpaqueToken(token))
|
|
100
|
+
return { kind: 'passthrough', jwt: token };
|
|
101
|
+
const payload = await unwrapToken(token, keyB64url);
|
|
102
|
+
if (!payload)
|
|
103
|
+
return { kind: 'invalid', reason: 'tampered' };
|
|
104
|
+
if (payload.e < Math.floor(Date.now() / 1000))
|
|
105
|
+
return { kind: 'invalid', reason: 'expired' };
|
|
106
|
+
return { kind: 'unwrapped', jwt: payload.j, payload };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=opaque-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opaque-token.js","sourceRoot":"","sources":["../src/opaque-token.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export type AccountType = 'PERSONAL' | 'PRO' | 'ADMIN';
|
|
2
|
+
export interface Account {
|
|
3
|
+
id: string;
|
|
4
|
+
owner_id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
type: AccountType;
|
|
7
|
+
created_at: string;
|
|
8
|
+
updated_at: string;
|
|
9
|
+
}
|
|
10
|
+
/** Top-level organisational unit. A user creates a journal and becomes its owner. */
|
|
11
|
+
export interface Journal {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string | null;
|
|
15
|
+
account_id: string;
|
|
16
|
+
is_public: boolean;
|
|
17
|
+
public_slug: string | null;
|
|
18
|
+
created_at: string;
|
|
19
|
+
updated_at: string;
|
|
20
|
+
}
|
|
21
|
+
/** Access control record linking a user to a journal with a role. */
|
|
22
|
+
export interface JournalMember {
|
|
23
|
+
id: string;
|
|
24
|
+
journal_id: string;
|
|
25
|
+
user_id: string;
|
|
26
|
+
role: 'owner' | 'member';
|
|
27
|
+
created_at: string;
|
|
28
|
+
}
|
|
29
|
+
/** Journal entry scoped to a journal. Identified user-facing by `index`. */
|
|
30
|
+
export interface Entry {
|
|
31
|
+
id: string;
|
|
32
|
+
journal_id: string;
|
|
33
|
+
index: number;
|
|
34
|
+
summary: string;
|
|
35
|
+
what_changed: string;
|
|
36
|
+
client?: string | null;
|
|
37
|
+
created_by: string | null;
|
|
38
|
+
created_at: string;
|
|
39
|
+
updated_at: string;
|
|
40
|
+
}
|
|
41
|
+
/** Slim entry shape returned by the list endpoint when `include=body` is absent. */
|
|
42
|
+
export interface EntrySummary {
|
|
43
|
+
id: string;
|
|
44
|
+
journal_id: string;
|
|
45
|
+
index: number;
|
|
46
|
+
summary: string;
|
|
47
|
+
created_at: string;
|
|
48
|
+
}
|
|
49
|
+
/** Email-based invitation for journal sharing. */
|
|
50
|
+
export interface Invitation {
|
|
51
|
+
id: string;
|
|
52
|
+
journal_id: string;
|
|
53
|
+
invited_by: string;
|
|
54
|
+
email: string;
|
|
55
|
+
token: string;
|
|
56
|
+
created_at: string;
|
|
57
|
+
accepted_at: string | null;
|
|
58
|
+
revoked_at: string | null;
|
|
59
|
+
}
|
|
60
|
+
export interface CreateAccountRequest {
|
|
61
|
+
name?: string | undefined;
|
|
62
|
+
}
|
|
63
|
+
export interface CreateJournalRequest {
|
|
64
|
+
account_id?: string | undefined;
|
|
65
|
+
name: string;
|
|
66
|
+
description?: string | undefined;
|
|
67
|
+
}
|
|
68
|
+
export interface UpdateJournalRequest {
|
|
69
|
+
name?: string | undefined;
|
|
70
|
+
description?: string | null | undefined;
|
|
71
|
+
is_public?: boolean | undefined;
|
|
72
|
+
}
|
|
73
|
+
export interface CreateEntryRequest {
|
|
74
|
+
summary: string;
|
|
75
|
+
what_changed: string;
|
|
76
|
+
client?: string;
|
|
77
|
+
}
|
|
78
|
+
export interface UpdateEntryRequest {
|
|
79
|
+
summary?: string | undefined;
|
|
80
|
+
what_changed?: string | undefined;
|
|
81
|
+
}
|
|
82
|
+
export interface CreateInvitationRequest {
|
|
83
|
+
email: string;
|
|
84
|
+
}
|
|
85
|
+
export interface AcceptInvitationRequest {
|
|
86
|
+
token: string;
|
|
87
|
+
}
|
|
88
|
+
export interface PaginatedResponse<T> {
|
|
89
|
+
data: T[];
|
|
90
|
+
total: number;
|
|
91
|
+
offset: number;
|
|
92
|
+
limit: number;
|
|
93
|
+
}
|
|
94
|
+
export interface ApiError {
|
|
95
|
+
error: {
|
|
96
|
+
code: string;
|
|
97
|
+
message: string;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@workjournal/shared",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared types, constants, and credential helpers for the Workjournal CLI and MCP server.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./credentials": {
|
|
13
|
+
"types": "./dist/credentials.d.ts",
|
|
14
|
+
"import": "./dist/credentials.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/workjournal-pro/workjournal.git",
|
|
27
|
+
"directory": "packages/shared"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/workjournal-pro/workjournal/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://workjournal.pro",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"workjournal",
|
|
35
|
+
"shared",
|
|
36
|
+
"types"
|
|
37
|
+
],
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "22.15.29",
|
|
40
|
+
"typescript": "5.8.3"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc --project tsconfig.json",
|
|
44
|
+
"check": "tsc --noEmit"
|
|
45
|
+
}
|
|
46
|
+
}
|