@tallpond/cli 0.0.3 → 0.0.5

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 (4) hide show
  1. package/README.md +18 -1
  2. package/cli.js +51 -4
  3. package/index.js +4 -0
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -72,7 +72,8 @@ export default async (ctx: FunctionContext, args: { resourceId: string; move: un
72
72
  ```
73
73
 
74
74
  The ctx surface is exactly `userId`, `resourceId`, `fn`, `invocationId`,
75
- `db.query`/`db.batch` (raw `/v1/db` wire shape), and `gateway(path, body)`
75
+ `db.query`/`db.batch` (raw `/v1/db` wire shape), and `gateway(path, body?, opts?)`
76
+ (POST by default, `{ method: 'GET' }` for read routes) —
76
77
  annotate with `FunctionContext` so the compiler enforces it. Full contract:
77
78
  <https://tallpond.com/docs/functions/>.
78
79
 
@@ -82,6 +83,22 @@ scanned, and handlers can import from them freely (everything is bundled). A
82
83
  top-level file without a default export is skipped with a warning rather than
83
84
  deployed.
84
85
 
86
+ ## `tallpond test-session [--user name]`
87
+
88
+ End-to-end testing without a browser: mints a bearer token for a synthetic
89
+ test user of your app. Test users have no wallet — their usage bills your own
90
+ balance directly (bounded by your per-app budget), and tokens expire after
91
+ 24h. The token alone goes to stdout:
92
+
93
+ ```sh
94
+ ALICE=$(tallpond test-session --user alice)
95
+ curl -H "Authorization: Bearer $ALICE" https://api.tallpond.com/v1/users/me
96
+ ```
97
+
98
+ It authenticates on every user-facing route — tables, resources, functions,
99
+ files, AI — as that user, metering normally. Mint two names for multi-user
100
+ flows.
101
+
85
102
  Full command reference: <https://tallpond.com> → docs → CLI.
86
103
 
87
104
  ## License
package/cli.js CHANGED
@@ -306,6 +306,9 @@ function deployFunctionsAsDev(gatewayUrl, token, appId, bundle, fetcher = fetch)
306
306
  bundle
307
307
  );
308
308
  }
309
+ function createTestSession(gatewayUrl, token, appId, name, fetcher = fetch) {
310
+ return request(fetcher, gatewayUrl, token, "POST", `dev/apps/${appId}/test-users`, { name });
311
+ }
309
312
  function collectBundleFiles(dir) {
310
313
  const out = [];
311
314
  const walk = (d) => {
@@ -382,11 +385,15 @@ function decodeInvocation(token) {
382
385
  function makeCtx(env, token) {
383
386
  const fetchImpl = env.TALLPOND_FETCH ?? fetch
384
387
  const base = String(env.TALLPOND_GATEWAY_URL ?? '').replace(/\\/$/, '')
385
- async function call(path, body) {
388
+ async function call(path, body, opts) {
389
+ const method = (opts && opts.method) || 'POST'
390
+ const bodyless = method === 'GET' || method === 'HEAD'
391
+ const headers = { authorization: 'Bearer ' + token }
392
+ if (!bodyless) headers['content-type'] = 'application/json'
386
393
  const res = await fetchImpl(base + path, {
387
- method: 'POST',
388
- headers: { 'content-type': 'application/json', authorization: 'Bearer ' + token },
389
- body: JSON.stringify(body),
394
+ method,
395
+ headers,
396
+ body: bodyless ? undefined : JSON.stringify(body),
390
397
  })
391
398
  const data = await res.json().catch(() => null)
392
399
  if (!res.ok) {
@@ -508,6 +515,7 @@ Usage:
508
515
  tallpond apps list List your apps
509
516
  tallpond deploy [schemaFile] Deploy the app: schema + functions/ + built bundle
510
517
  tallpond typegen [schemaFile] Generate row types (--out tallpond-env.d.ts)
518
+ tallpond test-session Mint a bearer token for a synthetic test user
511
519
  tallpond help Show this help
512
520
 
513
521
  Common flags:
@@ -521,6 +529,10 @@ deploy flags:
521
529
  --no-bundle deploy the schema only
522
530
  schemaFile defaults to ./.tallpond.schema.ts (skipped if absent)
523
531
 
532
+ test-session flags:
533
+ --user <name> which test user (default "default"; same name = same user)
534
+ --json print the full response as JSON instead of just the token
535
+
524
536
  Platform/CI escape hatch (bypasses login; uses the shared deploy token):
525
537
  --app-id <id> --deployment-id <id> --token <token>
526
538
  [env TALLPOND_APP_ID, TALLPOND_DEPLOYMENT_ID, TALLPOND_DEPLOY_TOKEN]
@@ -539,6 +551,7 @@ async function main(argv) {
539
551
  if (command === "create") return await runAppsCreate(argv.slice(1));
540
552
  if (command === "deploy") return await runDeploy(argv.slice(1));
541
553
  if (command === "typegen") return await runTypegen(argv.slice(1));
554
+ if (command === "test-session") return await runTestSession(argv.slice(1));
542
555
  } catch (e) {
543
556
  if (e instanceof DevApiError) {
544
557
  if (e.status === 401) {
@@ -816,6 +829,40 @@ ${renderBlockedChanges(result.changes)}
816
829
  }
817
830
  return 1;
818
831
  }
832
+ async function runTestSession(args) {
833
+ const { values } = parseArgs({
834
+ args,
835
+ allowPositionals: false,
836
+ options: {
837
+ "gateway-url": { type: "string" },
838
+ user: { type: "string" },
839
+ json: { type: "boolean" }
840
+ }
841
+ });
842
+ const project = readProjectConfig();
843
+ if (!project) {
844
+ process.stderr.write(`error: no ${PROJECT_CONFIG_FILE} here \u2014 run \`tallpond apps create <name>\` first
845
+ `);
846
+ return 1;
847
+ }
848
+ const gatewayUrl = resolveGatewayUrl(values["gateway-url"] ?? project.gatewayUrl);
849
+ const token = requireToken(gatewayUrl);
850
+ const session = await createTestSession(gatewayUrl, token, project.appId, values.user ?? "default");
851
+ if (values.json) {
852
+ process.stdout.write(`${JSON.stringify(session, null, 2)}
853
+ `);
854
+ return 0;
855
+ }
856
+ process.stderr.write(
857
+ `test user ${session.user_id} \u2014 usage bills your own balance (token expires ${session.expires_at})
858
+ use it as a bearer token, e.g.
859
+ curl -H "Authorization: Bearer <token>" ${gatewayUrl}/v1/users/me
860
+ `
861
+ );
862
+ process.stdout.write(`${session.token}
863
+ `);
864
+ return 0;
865
+ }
819
866
  async function runTypegen(args) {
820
867
  const { values, positionals } = parseArgs({
821
868
  args,
package/index.js CHANGED
@@ -241,6 +241,9 @@ function deployFunctionsAsDev(gatewayUrl, token, appId, bundle, fetcher = fetch)
241
241
  bundle
242
242
  );
243
243
  }
244
+ function createTestSession(gatewayUrl, token, appId, name, fetcher = fetch) {
245
+ return request(fetcher, gatewayUrl, token, "POST", `dev/apps/${appId}/test-users`, { name });
246
+ }
244
247
  function collectBundleFiles(dir) {
245
248
  const out = [];
246
249
  const walk = (d) => {
@@ -340,6 +343,7 @@ export {
340
343
  PROJECT_CONFIG_FILE,
341
344
  collectBundleFiles,
342
345
  createApp,
346
+ createTestSession,
343
347
  deploy,
344
348
  deployFunctionsAsDev,
345
349
  deploySchemaAsDev,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tallpond/cli",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "The tallpond developer CLI — sign in, register an app, and deploy schema + frontend with one command.",
5
5
  "license": "MIT",
6
6
  "repository": {