minutework 0.1.35 → 0.1.36

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.
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@expo/metro-runtime": "~56.0.13",
15
+ "@minutework/native-auth": "^0.1.0",
15
16
  "expo": "~56.0.8",
16
17
  "expo-asset": "~56.0.15",
17
18
  "expo-constants": "~56.0.16",
@@ -1,251 +1,48 @@
1
- // MinuteWork substrate. Thin layer — do not put product UI/logic here.
2
- //
3
- // MinuteWork native token client. Implements the browser-assisted device flow
4
- // against the SHIPPED platform native-token endpoints (`/api/v1/native/session/*`).
5
- //
6
- // Authentication is owned by the MinuteWork platform. This client only *obtains
7
- // and uses* a platform-issued bearer token — there is NO JWT minting, NO password
8
- // handling, NO local user table, and NO parallel auth stack here. Token plaintext
9
- // is never logged.
10
- //
11
- // ----------------------------------------------------------------------------
12
- // Device flow (browser-assisted authorization):
13
- // ----------------------------------------------------------------------------
14
- // 1. authorize(): generate a PKCE code_verifier + S256 code_challenge, open the
15
- // platform authorize URL in a system browser (`expo-web-browser`) with the
16
- // app's deep-link redirect_uri + code_challenge + an anti-forgery `state`.
17
- // The platform authenticates the human and redirects back to redirect_uri
18
- // with a short-lived single-use `code` (and the echoed `state`).
19
- // 2. exchange(code, verifier): POST {code, code_verifier, redirect_uri} to
20
- // `/token-exchange/`; the platform returns the access/refresh token pair.
21
- // 3. store the pair in the device keychain via `mwSession.setTokens(...)`.
22
- // 4. for every platform call, send `Authorization: Bearer <access>`. On a 401,
23
- // POST the stored refresh token to `/refresh/`, persist the rotated pair,
24
- // and retry once.
25
- // 5. logout(): POST `/logout/` to revoke, then `mwSession.clearTokens()`.
26
- //
27
- // This is the DIRECT platform path — there is no tenant-app BFF and no
28
- // server-owned cookie in front of the mobile client.
29
-
30
1
  import * as Crypto from "expo-crypto";
31
2
  import * as Linking from "expo-linking";
32
3
  import * as WebBrowser from "expo-web-browser";
33
-
34
4
  import {
35
- nativeSessionSchema,
36
- nativeTokenPairSchema,
37
- type NativeSession,
38
- type NativeTokenPair,
39
- } from "@/mw/contracts";
40
- import { platformNativeEndpoints } from "@/mw/endpoints";
5
+ createNativeAuthClient,
6
+ type NativeBrowser,
7
+ type NativeCrypto,
8
+ } from "@minutework/native-auth";
9
+
10
+ import { mwEnv } from "@/mw/env";
41
11
  import { mwSession } from "@/mw/session";
42
12
 
43
13
  // The deep-link path the platform redirects back to. The scheme is read from
44
14
  // `app.json` ("scheme") by expo-linking; the dev configures that scheme.
45
15
  const REDIRECT_PATH = "auth/native-callback";
46
16
 
47
- // Result of a single authorize round-trip: the one-time code plus the PKCE
48
- // verifier that must be presented at exchange.
49
- export interface NativeAuthorizationResult {
50
- code: string;
51
- codeVerifier: string;
52
- redirectUri: string;
53
- }
54
-
55
- function base64UrlFromBytes(bytes: Uint8Array): string {
56
- let binary = "";
57
- for (const byte of bytes) {
58
- binary += String.fromCharCode(byte);
59
- }
60
- // btoa is available in the Hermes/React Native runtime.
61
- return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
62
- }
63
-
64
- // PKCE code_verifier: 32 random bytes -> base64url (43 chars, no padding). This
65
- // is URL-safe and whitespace-free, matching the platform's `.strip()`ed verifier
66
- // and its 255-char cap.
67
- function generateCodeVerifier(): string {
68
- return base64UrlFromBytes(Crypto.getRandomBytes(32));
69
- }
70
-
71
- // S256 challenge: base64url(SHA-256(verifier)). Mirrors the platform's
72
- // `build_pkce_code_challenge` (sha256 digest -> urlsafe base64 -> strip "=").
73
- async function deriveCodeChallenge(codeVerifier: string): Promise<string> {
74
- const digestBase64 = await Crypto.digestStringAsync(
75
- Crypto.CryptoDigestAlgorithm.SHA256,
76
- codeVerifier,
77
- { encoding: Crypto.CryptoEncoding.BASE64 },
78
- );
79
- return digestBase64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
80
- }
81
-
82
- function buildAuthorizeUrl(params: {
83
- redirectUri: string;
84
- state: string;
85
- codeChallenge: string;
86
- }): string {
87
- const url = new URL(platformNativeEndpoints.authorize);
88
- url.searchParams.set("redirect_uri", params.redirectUri);
89
- url.searchParams.set("state", params.state);
90
- url.searchParams.set("code_challenge", params.codeChallenge);
91
- return url.toString();
92
- }
93
-
94
- async function postJson(url: string, body: Record<string, unknown>): Promise<Response> {
95
- return fetch(url, {
96
- method: "POST",
97
- headers: {
98
- "Content-Type": "application/json",
99
- Accept: "application/json",
100
- },
101
- body: JSON.stringify(body),
102
- });
103
- }
104
-
105
- // Surface a platform error without leaking response internals. The platform
106
- // returns `{detail: "..."}` for native auth failures.
107
- async function readErrorDetail(response: Response, fallback: string): Promise<string> {
108
- try {
109
- const data = (await response.json()) as { detail?: unknown };
110
- if (data && typeof data.detail === "string" && data.detail.length > 0) {
111
- return data.detail;
112
- }
113
- } catch {
114
- // ignore non-JSON bodies
115
- }
116
- return `${fallback} (HTTP ${response.status})`;
117
- }
118
-
119
- export const mwClient = {
120
- // Step 1: open the platform authorize URL in a system browser and resolve with
121
- // the single-use authorization code + the PKCE verifier to exchange it.
122
- async authorize(): Promise<NativeAuthorizationResult> {
123
- const redirectUri = Linking.createURL(REDIRECT_PATH);
124
- const codeVerifier = generateCodeVerifier();
125
- const codeChallenge = await deriveCodeChallenge(codeVerifier);
126
- const state = base64UrlFromBytes(Crypto.getRandomBytes(16));
127
-
128
- const authorizeUrl = buildAuthorizeUrl({ redirectUri, state, codeChallenge });
129
- const result = await WebBrowser.openAuthSessionAsync(authorizeUrl, redirectUri);
130
-
131
- if (result.type !== "success" || !result.url) {
132
- throw new Error("Sign in was cancelled before the platform returned a code.");
133
- }
134
-
135
- const returned = new URL(result.url);
136
- const returnedState = returned.searchParams.get("state");
137
- if (returnedState !== state) {
138
- // Anti-forgery: the platform must echo back the exact state we sent.
139
- throw new Error("Sign in failed: callback state did not match the request.");
140
- }
141
- const code = returned.searchParams.get("code");
142
- if (!code) {
143
- throw new Error("Sign in failed: the platform callback did not include a code.");
144
- }
145
-
146
- return { code, codeVerifier, redirectUri };
147
- },
148
-
149
- // Step 2: exchange the authorization code for a platform-issued token pair and
150
- // persist it to the device keychain.
151
- async exchange(
152
- code: string,
153
- codeVerifier: string,
154
- redirectUri: string,
155
- ): Promise<NativeTokenPair> {
156
- const response = await postJson(platformNativeEndpoints.tokenExchange, {
157
- code,
158
- code_verifier: codeVerifier,
159
- redirect_uri: redirectUri,
160
- });
161
- if (!response.ok) {
162
- throw new Error(await readErrorDetail(response, "Token exchange failed"));
163
- }
164
- const pair = nativeTokenPairSchema.parse(await response.json());
165
- await mwSession.setTokens(
166
- pair.access_token,
167
- pair.refresh_token,
168
- pair.access_token_expires_at,
169
- );
170
- return pair;
17
+ const nativeCrypto: NativeCrypto = {
18
+ randomBytes(length: number): Uint8Array {
19
+ return Crypto.getRandomBytes(length);
171
20
  },
172
-
173
- // Step 4 (on 401 / proactive): rotate the access token using the stored refresh
174
- // token and persist the rotated pair.
175
- async refresh(): Promise<NativeTokenPair> {
176
- const stored = await mwSession.getTokens();
177
- if (!stored) {
178
- throw new Error("No stored session to refresh. Sign in again.");
179
- }
180
- const response = await postJson(platformNativeEndpoints.refresh, {
181
- refresh_token: stored.refresh,
182
- });
183
- if (!response.ok) {
184
- // Refresh failure means the session is dead; clear it so the app routes
185
- // back to login.
186
- await mwSession.clearTokens();
187
- throw new Error(await readErrorDetail(response, "Session refresh failed"));
188
- }
189
- const pair = nativeTokenPairSchema.parse(await response.json());
190
- await mwSession.setTokens(
191
- pair.access_token,
192
- pair.refresh_token,
193
- pair.access_token_expires_at,
21
+ async sha256Base64Url(input: string): Promise<string> {
22
+ const digestBase64 = await Crypto.digestStringAsync(
23
+ Crypto.CryptoDigestAlgorithm.SHA256,
24
+ input,
25
+ { encoding: Crypto.CryptoEncoding.BASE64 },
194
26
  );
195
- return pair;
27
+ return digestBase64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
196
28
  },
29
+ };
197
30
 
198
- // Resolve the active session (user + active tenant + memberships) from the
199
- // stored token, auto-refreshing once on a 401 then retrying.
200
- async loadSession(): Promise<NativeSession> {
201
- const stored = await mwSession.getTokens();
202
- if (!stored) {
203
- throw new Error("Not signed in.");
204
- }
205
-
206
- const meOnce = async (accessToken: string): Promise<Response> =>
207
- fetch(platformNativeEndpoints.me, {
208
- method: "GET",
209
- headers: {
210
- Accept: "application/json",
211
- Authorization: `Bearer ${accessToken}`,
212
- },
213
- });
214
-
215
- let response = await meOnce(stored.access);
216
- if (response.status === 401) {
217
- // Single refresh-and-retry on an expired/invalid access token.
218
- const rotated = await this.refresh();
219
- response = await meOnce(rotated.access_token);
220
- }
221
- if (!response.ok) {
222
- throw new Error(await readErrorDetail(response, "Failed to load session"));
223
- }
224
- return nativeSessionSchema.parse(await response.json());
31
+ const nativeBrowser: NativeBrowser = {
32
+ createRedirectUri(): string {
33
+ return Linking.createURL(REDIRECT_PATH);
225
34
  },
226
-
227
- // Step 5: revoke the token pair on the platform, then clear local secure
228
- // storage. Local state is always cleared, even if the revoke call fails.
229
- async logout(): Promise<void> {
230
- const stored = await mwSession.getTokens();
231
- try {
232
- if (stored) {
233
- await fetch(platformNativeEndpoints.logout, {
234
- method: "POST",
235
- headers: {
236
- "Content-Type": "application/json",
237
- Accept: "application/json",
238
- Authorization: `Bearer ${stored.access}`,
239
- },
240
- body: JSON.stringify({}),
241
- });
242
- }
243
- } catch {
244
- // Best-effort revoke; never block local sign-out on a network error.
245
- } finally {
246
- await mwSession.clearTokens();
247
- }
35
+ async openAuthSession(url: string, redirectUri: string): Promise<string | null> {
36
+ const result = await WebBrowser.openAuthSessionAsync(url, redirectUri);
37
+ return result.type === "success" && result.url ? result.url : null;
248
38
  },
249
39
  };
250
40
 
41
+ export const mwClient = createNativeAuthClient({
42
+ platformBaseUrl: mwEnv.platformBaseUrl,
43
+ storage: mwSession,
44
+ crypto: nativeCrypto,
45
+ browser: nativeBrowser,
46
+ });
47
+
251
48
  export type MwClient = typeof mwClient;
@@ -8,7 +8,11 @@
8
8
 
9
9
  import * as SecureStore from "expo-secure-store";
10
10
 
11
- import { storedTokensSchema, type StoredTokens } from "@/mw/contracts";
11
+ import {
12
+ storedTokensSchema,
13
+ type NativeTokenStorage,
14
+ type StoredTokens,
15
+ } from "@minutework/native-auth";
12
16
 
13
17
  const TOKEN_KEY = "mw.native.token_pair";
14
18
 
@@ -45,6 +49,6 @@ export const mwSession = {
45
49
  async clearTokens(): Promise<void> {
46
50
  await SecureStore.deleteItemAsync(TOKEN_KEY, SECURE_STORE_OPTIONS);
47
51
  },
48
- };
52
+ } satisfies NativeTokenStorage;
49
53
 
50
54
  export type MwSession = typeof mwSession;
@@ -1,4 +1,4 @@
1
- import type { CompileGraph, RuntimeAppReleaseMetadata, SeedDataManifestDocument } from "@minutework/schema-compiler";
1
+ import type { CompileGraph, PlatformChannelManifestDocument, RuntimeAppReleaseMetadata, SeedDataManifestDocument } from "@minutework/schema-compiler";
2
2
  export declare const MINUTEWORK_RUNTIME_APP_PACKAGE_VERSION = "MinuteWorkRuntimeAppPackageV1";
3
3
  export type RuntimeAppSourceBundleFile = {
4
4
  contentBase64: string;
@@ -14,6 +14,7 @@ export type RuntimeAppPackageArtifact = {
14
14
  sha256: string;
15
15
  };
16
16
  release: RuntimeAppReleaseMetadata;
17
+ platformChannelManifest: PlatformChannelManifestDocument | null;
17
18
  seedDataManifest: SeedDataManifestDocument | null;
18
19
  sourceBundle: {
19
20
  files: RuntimeAppSourceBundleFile[];
@@ -16,6 +16,7 @@ export async function buildRuntimeAppPackage(options) {
16
16
  sidecarRoot,
17
17
  });
18
18
  const seedDataManifest = options.compileGraph.documents.seedDataManifests[0] ?? null;
19
+ const platformChannelManifest = options.compileGraph.documents.platformChannelManifests[0] ?? null;
19
20
  const artifactSetDigest = sha256Hex(JSON.stringify({
20
21
  compileGraph: options.compileGraph.documents,
21
22
  dependencyExport: {
@@ -24,7 +25,10 @@ export async function buildRuntimeAppPackage(options) {
24
25
  },
25
26
  release: options.releaseMetadata,
26
27
  sourceBundle: {
27
- files: sourceBundle.files.map((file) => ({ path: file.path, sha256: file.sha256 })),
28
+ files: sourceBundle.files.map((file) => ({
29
+ path: file.path,
30
+ sha256: file.sha256,
31
+ })),
28
32
  sha256: sourceBundle.sha256,
29
33
  },
30
34
  template,
@@ -35,6 +39,7 @@ export async function buildRuntimeAppPackage(options) {
35
39
  compileGraph: options.compileGraph,
36
40
  dependencyExport,
37
41
  release: options.releaseMetadata,
42
+ platformChannelManifest,
38
43
  seedDataManifest,
39
44
  sourceBundle,
40
45
  template,
@@ -43,13 +48,16 @@ export async function buildRuntimeAppPackage(options) {
43
48
  }
44
49
  export function buildRuntimePackagePayload(packageArtifact) {
45
50
  const payload = JSON.parse(JSON.stringify(packageArtifact));
46
- // Drop the camelCase artifact-surface field. The runtime install pipe
47
- // consumes the snake_case `seed_data_manifest` key (see
48
- // apps/mwv3-runtime-dj/apps/runtime_app_host/deployment_services.py:416).
51
+ // Drop camelCase artifact-surface fields. The runtime install pipe
52
+ // consumes snake_case manifest keys.
49
53
  delete payload.seedDataManifest;
54
+ delete payload.platformChannelManifest;
50
55
  if (packageArtifact.seedDataManifest !== null) {
51
56
  payload.seed_data_manifest = packageArtifact.seedDataManifest;
52
57
  }
58
+ if (packageArtifact.platformChannelManifest !== null) {
59
+ payload.platform_channel_manifest = packageArtifact.platformChannelManifest;
60
+ }
53
61
  return payload;
54
62
  }
55
63
  async function buildSourceBundle(root) {
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-package.js","sourceRoot":"","sources":["../src/runtime-package.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime-package.js","sourceRoot":"","sources":["../src/runtime-package.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAStC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,CAAC,MAAM,sCAAsC,GACjD,+BAA+B,CAAC;AAoClC,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAK5C;IACC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAC3B,OAAO,CAAC,aAAa,EACrB,OAAO,CAAC,eAAe,CAAC,WAAW,CACpC,CAAC;IACF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CACb,CAAC;IAC7B,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC1D,MAAM,gBAAgB,GAAG,MAAM,qBAAqB,CAAC;QACnD,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,WAAW;KACZ,CAAC,CAAC;IACH,MAAM,gBAAgB,GACpB,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC9D,MAAM,uBAAuB,GAC3B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACrE,MAAM,iBAAiB,GAAG,SAAS,CACjC,IAAI,CAAC,SAAS,CAAC;QACb,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,SAAS;QAC5C,gBAAgB,EAAE;YAChB,IAAI,EAAE,gBAAgB,CAAC,IAAI;YAC3B,MAAM,EAAE,gBAAgB,CAAC,MAAM;SAChC;QACD,OAAO,EAAE,OAAO,CAAC,eAAe;QAChC,YAAY,EAAE;YACZ,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACvC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC,CAAC;YACH,MAAM,EAAE,YAAY,CAAC,MAAM;SAC5B;QACD,QAAQ;QACR,OAAO,EAAE,sCAAsC;KAChD,CAAC,CACH,CAAC;IAEF,OAAO;QACL,iBAAiB;QACjB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,gBAAgB;QAChB,OAAO,EAAE,OAAO,CAAC,eAAe;QAChC,uBAAuB;QACvB,gBAAgB;QAChB,YAAY;QACZ,QAAQ;QACR,OAAO,EAAE,sCAAsC;KAChD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,eAA0C;IAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAGzD,CAAC;IACF,mEAAmE;IACnE,qCAAqC;IACrC,OAAO,OAAO,CAAC,gBAAgB,CAAC;IAChC,OAAO,OAAO,CAAC,uBAAuB,CAAC;IACvC,IAAI,eAAe,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,CAAC,kBAAkB,GAAG,eAAe,CAAC,gBAAgB,CAAC;IAChE,CAAC;IACD,IAAI,eAAe,CAAC,uBAAuB,KAAK,IAAI,EAAE,CAAC;QACrD,OAAO,CAAC,yBAAyB,GAAG,eAAe,CAAC,uBAAuB,CAAC;IAC9E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,IAAY;IAEZ,MAAM,KAAK,GAAiC,EAAE,CAAC;IAE/C,KAAK,UAAU,KAAK,CAAC,WAAmB;QACtC,MAAM,YAAY,GAAG,qBAAqB,CACxC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CACjC,CAAC;QACF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CACpE,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,YAAY,CAAC,YAAY,CAAC,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC9C,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CACpE,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC;YACT,aAAa,EAAE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC1C,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,OAAO;QACL,KAAK;QACL,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,EAAE,SAAS,CACf,IAAI,CAAC,SAAS,CACZ,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAChE,CACF;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,OAGpC;IACC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC/D,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACzD,OAAO;YACL,OAAO,EAAE,YAAY;YACrB,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE,SAAS,CAAC,YAAY,CAAC;SAChC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,KAA8B,CAAC;QAC7C,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CACnD,CAAC;IACF,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,QAAQ,CACf,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC,EAChD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CACtC,CAAC;QACF,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE,UAAU,IAAI,iBAAiB,CAAC;QACzE,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QACD,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,QAAQ,CACrC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAClC,MAAM,CACP,CAAC;QACF,OAAO;YACL,OAAO,EAAE,aAAa;YACtB,IAAI,EAAE,uBAAuB;YAC7B,MAAM,EAAE,SAAS,CAAC,aAAa,CAAC;SACjC,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,OAAe,EAAE,IAAc,EAAE,GAAW;IAC3E,OAAO,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB;IACxC,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,YAAY,CAAC;IACzD,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QACvB,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7B,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC;QAC/B,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7B,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC7B,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC1B,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC1B,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minutework",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "MinuteWork CLI for workspace scaffolding, local preview workflows, and hosted preview deploys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -401,6 +401,33 @@ export declare const SchemaStatusSchema: z.ZodObject<{
401
401
  mapping_id: z.ZodString;
402
402
  version: z.ZodLiteral<"OntologyMappingManifestV1">;
403
403
  }, z.core.$strict>>;
404
+ platformChannelManifests: z.ZodArray<z.ZodObject<{
405
+ channels: z.ZodArray<z.ZodObject<{
406
+ category: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
407
+ label: z.ZodOptional<z.ZodString>;
408
+ ordering: z.ZodOptional<z.ZodNumber>;
409
+ slug: z.ZodString;
410
+ }, z.core.$strict>]>;
411
+ category_label: z.ZodOptional<z.ZodString>;
412
+ category_ordering: z.ZodOptional<z.ZodNumber>;
413
+ customer_visibility: z.ZodEnum<{
414
+ hidden: "hidden";
415
+ visible: "visible";
416
+ }>;
417
+ label: z.ZodString;
418
+ landing_agent_ref: z.ZodOptional<z.ZodString>;
419
+ landing_thread_kind: z.ZodOptional<z.ZodEnum<{
420
+ "": "";
421
+ channel: "channel";
422
+ private: "private";
423
+ guest_shared: "guest_shared";
424
+ }>>;
425
+ landing_title: z.ZodOptional<z.ZodString>;
426
+ ordering: z.ZodNumber;
427
+ slug: z.ZodString;
428
+ }, z.core.$strict>>;
429
+ version: z.ZodLiteral<"1">;
430
+ }, z.core.$strict>>;
404
431
  projectionContracts: z.ZodArray<z.ZodObject<{
405
432
  app_id: z.ZodString;
406
433
  contract_id: z.ZodString;
@@ -1,79 +0,0 @@
1
- // MinuteWork substrate. Thin layer — do not put product UI/logic here.
2
- //
3
- // Zod schemas for the MinuteWork platform *native* session payloads. These match
4
- // the SHIPPED platform native-token slice (`/api/v1/native/session/*`) response
5
- // shapes exactly (DRF emits snake_case). They describe API responses, not product
6
- // data. Keep them aligned with the platform serializers in
7
- // `apps/mwv3-platform-dj/apps/gateway_api/serializers.py`:
8
- // - token pair -> IssuedNativeAppSessionTokenPairSerializer
9
- // - session/me -> TenantSessionResponseSerializer
10
- //
11
- // Schemas use `.passthrough()` so additive platform fields never break parsing;
12
- // the client only depends on the fields it reads.
13
-
14
- import { z } from "zod";
15
-
16
- // A tenant the authenticated user belongs to. Mirrors `_serialize_membership`
17
- // on the platform; only the load-bearing fields are constrained, the rest pass
18
- // through. `role` may be an empty string for a membership with no role.
19
- export const nativeMembershipSchema = z
20
- .object({
21
- tenant_id: z.string().min(1),
22
- tenant_slug: z.string(),
23
- tenant_name: z.string(),
24
- role: z.string(),
25
- })
26
- .passthrough();
27
-
28
- export const nativeActiveTenantSchema = nativeMembershipSchema;
29
-
30
- // Mirrors `_serialize_user`. `email` is not constrained to an email shape because
31
- // the platform may serialize a blank/non-email value.
32
- export const nativeUserSchema = z
33
- .object({
34
- id: z.string().min(1),
35
- username: z.string(),
36
- email: z.string(),
37
- })
38
- .passthrough();
39
-
40
- // Response of `/api/v1/native/session/me/` (and `/context/`):
41
- // `TenantSessionResponseSerializer`. `active_tenant_id` / `active_tenant` are
42
- // null when the user has no active membership.
43
- export const nativeSessionSchema = z
44
- .object({
45
- user: nativeUserSchema,
46
- active_tenant_id: z.string().nullable(),
47
- active_tenant: nativeActiveTenantSchema.nullable(),
48
- memberships: z.array(nativeMembershipSchema),
49
- onboarding_completed_for_active_workspace: z.boolean().nullable().optional(),
50
- })
51
- .passthrough();
52
-
53
- // Platform-issued bearer token pair returned by `/token-exchange/` and
54
- // `/refresh/`: `IssuedNativeAppSessionTokenPairSerializer`. `*_expires_at` are
55
- // ISO-8601 timestamps; the client uses the access expiry to refresh proactively.
56
- export const nativeTokenPairSchema = z
57
- .object({
58
- access_token: z.string().min(1),
59
- refresh_token: z.string().min(1),
60
- access_token_expires_at: z.string().min(1),
61
- refresh_token_expires_at: z.string().min(1),
62
- })
63
- .passthrough();
64
-
65
- // What we persist in the device keychain: the two opaque tokens plus the access
66
- // token's expiry (ISO-8601). This is the on-device shape, distinct from the wire
67
- // shape above.
68
- export const storedTokensSchema = z.object({
69
- access: z.string().min(1),
70
- refresh: z.string().min(1),
71
- expiresAt: z.string().min(1),
72
- });
73
-
74
- export type NativeMembership = z.infer<typeof nativeMembershipSchema>;
75
- export type NativeActiveTenant = z.infer<typeof nativeActiveTenantSchema>;
76
- export type NativeUser = z.infer<typeof nativeUserSchema>;
77
- export type NativeSession = z.infer<typeof nativeSessionSchema>;
78
- export type NativeTokenPair = z.infer<typeof nativeTokenPairSchema>;
79
- export type StoredTokens = z.infer<typeof storedTokensSchema>;
@@ -1,42 +0,0 @@
1
- // MinuteWork substrate. Thin layer — do not put product UI/logic here.
2
- //
3
- // Builds absolute URLs for the MinuteWork *platform native* session endpoints.
4
- //
5
- // These endpoints are the DIRECT platform API surface for native clients
6
- // (`/api/v1/native/...`). The mobile app authenticates with a platform-issued
7
- // bearer token obtained through a browser-assisted device flow, then calls the
8
- // platform directly. This is intentionally NOT the tenant-app BFF cookie path
9
- // (the Next.js `platform_session_bff` profile) — there is no per-app server in
10
- // front of the mobile client.
11
- //
12
- // These routes are SHIPPED by the platform native-token slice and are called by
13
- // the real device-flow client in `src/mw/client.ts`.
14
-
15
- import { mwEnv } from "@/mw/env";
16
-
17
- const platformBaseUrl = new URL(
18
- mwEnv.platformBaseUrl.endsWith("/")
19
- ? mwEnv.platformBaseUrl
20
- : `${mwEnv.platformBaseUrl}/`,
21
- );
22
-
23
- function buildPlatformEndpoint(path: string): string {
24
- return new URL(path.replace(/^\//, ""), platformBaseUrl).toString();
25
- }
26
-
27
- export const platformNativeEndpoints = {
28
- // Begin the browser-assisted device authorization flow.
29
- authorize: buildPlatformEndpoint("/api/v1/native/session/authorize/"),
30
- // Exchange the authorization result for an access/refresh token pair.
31
- tokenExchange: buildPlatformEndpoint("/api/v1/native/session/token-exchange/"),
32
- // Rotate an expired access token using the refresh token.
33
- refresh: buildPlatformEndpoint("/api/v1/native/session/refresh/"),
34
- // Resolve the current authenticated principal (user + active tenant).
35
- me: buildPlatformEndpoint("/api/v1/native/session/me/"),
36
- // Resolve / switch active tenant context for the session.
37
- context: buildPlatformEndpoint("/api/v1/native/session/context/"),
38
- // Revoke the current token pair.
39
- logout: buildPlatformEndpoint("/api/v1/native/session/logout/"),
40
- } as const;
41
-
42
- export type PlatformNativeEndpoint = keyof typeof platformNativeEndpoints;