Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/code.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ the integration (`code:execute` for `invoke`).
| `norbix code qualifiers --integration <int_…> --function <id>` | the aliases and versions: name, kind (Alias / Version), the version an alias points at | `GET /qualifiers` |
| `norbix code invoke --integration <int_…> --function <id> [--qualifier <alias\|version>] [--payload '<json>' \| --payload-file <file>] [--async] [--run-as <usr_…>] [--config '<json>'] [--dry-run]` | Sync (default): the status code, the duration in ms, the function's output and the provider's request id. `--async`: that the call was accepted | `POST /invoke` |
| `norbix code event-sample --source <database\|membership\|files\|payments\|ai\|scheduler\|manual> [--event <name>] [--schema <sch_…>]` | the full envelope with sample data — the fixture for `sam local invoke`, `func start` or the Functions Framework | `GET /event-sample` |
| `norbix code runs --trigger <trg_…> \| --task <tsk_…> [--limit <1-50>]` | the last runs, newest first: fired at, event, succeeded, status code, duration, error, request id — a run through the Fake provider also its `input`, the envelope the function received (`context.runAs.accessToken` masked, cut at 64 KB), pretty-printed under the row | `GET /runs` |
| `norbix code runs --trigger <trg_…> \| --task <tsk_…> [--limit <1-50>]` | the last runs, newest first: fired at, event, succeeded, status code, duration, error, request id — a run through the Sandbox provider (API value `Fake`) also its `input`, the envelope the function received (`context.runAs.accessToken` masked, cut at 64 KB), pretty-printed under the row | `GET /runs` |

`--json` on any of them prints the raw answer. `invoke` sends the function a
`manual.invoke` envelope with the payload in `data.payload`; `context.runAs` is
Expand Down Expand Up @@ -79,7 +79,7 @@ All paths below are under `/{version}/code/marketplace`.
| `norbix code marketplace functions add --connection <int_…> --key <key> [--name <text>] [--arguments '<json>'] [--arg k=v]… [--input name[:type[:required]]]…` | adds a function and prints the minted id | `POST /integrations/{id}/functions` |
| `norbix code marketplace functions enable\|disable\|delete <func_…> --connection <int_…>` | turns it on / off, deletes it | `POST …/enable`, `POST …/disable`, `DELETE …` |
| `norbix code marketplace functions invoke <func_…> [--payload '<json>' \| --payload-file <file>]` | calls it as you; prints `isSuccess`, `output`, `vendorRequestId` | `POST /functions/{func}/invoke` |
| `norbix code marketplace runs --function <func_…> \| --trigger <trg_…> \| --task <tsk_…> \| --connection <int_…> [--limit <1-50>] [--details]` | the last runs, newest first: `--function` every run of one function from every source (invoke, trigger, scheduler; 50 kept), `--trigger` / `--task` the runs it started (20 kept), `--connection` the tool calls an AI chat made on an MCP connection without a saved function (rows carry `integrationId` and `toolName`). A row has `status` (`ok` / `failed` / `skipped`), `durationMs`, `source`, `correlationId`, `hasDetails`; a Fake-vendor run also its `input` (secrets `***`), pretty-printed under the row. `--details` adds each run's log lines (input, steps, answer or error) for rows with `hasDetails: true`; any other row says "details need the project's logs on" | `GET /functions/runs`; `--details`: `GET /logs/audit?targetCorrelationId=…` per row |
| `norbix code marketplace runs --function <func_…> \| --trigger <trg_…> \| --task <tsk_…> \| --connection <int_…> [--limit <1-50>] [--details]` | the last runs, newest first: `--function` every run of one function from every source (invoke, trigger, scheduler; 50 kept), `--trigger` / `--task` the runs it started (20 kept), `--connection` the tool calls an AI chat made on an MCP connection without a saved function (rows carry `integrationId` and `toolName`). A row has `status` (`ok` / `failed` / `skipped`), `durationMs`, `source`, `correlationId`, `hasDetails`; a Sandbox-vendor run (API value `Fake`) also its `input` (secrets `***`), pretty-printed under the row. `--details` adds each run's log lines (input, steps, answer or error) for rows with `hasDetails: true`; any other row says "details need the project's logs on" | `GET /functions/runs`; `--details`: `GET /logs/audit?targetCorrelationId=…` per row |

Notes:

Expand Down
9 changes: 4 additions & 5 deletions docs/email.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Every command is covered by `tests/email-routes.test.ts`, which runs it through
the real SDK with `fetch` replaced and checks the verb and path it sends (so a
wrong route token fails a test). `tests/email.test.ts` and
`tests/email-existing.test.ts` also check the request fields. No test contacts
a mail service; the only provider a test saves is **Fake**.
a mail service; the only provider a test saves is **Sandbox** (API value `Fake`).

All paths below are under `/{version}/notifications/email`, except
`campaign messages` (the gateway spells that route `/notifications/emails/…`).
Expand Down Expand Up @@ -39,16 +39,15 @@ first two, for scripts that treat every module alike.
| `norbix email integration confirm-delivery <id>` | confirm the test e-mail reached a person | `POST /integrations/confirm-human-delivery` |
| `norbix email integration domain-health <id>` | check SPF / DKIM / DMARC of the sending domain (read only) | `POST /integrations/domain-health` |

`--provider` is one of `Fake`, `Smtp`, `SendGrid`, `MailGun`, `AwsSes`. **Fake**
needs nothing else: it accepts every send and contacts no mail service, so
`--provider` is one of `Sandbox`, `Smtp`, `SendGrid`, `MailGun`, `AwsSes`. **Sandbox** (sent to the API as `Fake`) needs nothing else: it accepts every send and contacts no mail service, so
nothing reaches a real inbox — use it while you develop. A project can hold one
Fake and it has no update path: delete it and add it again. The real providers
Sandbox and it has no update path: delete it and add it again. The real providers
need a sender (`--from`) and their credentials: put the provider-specific
fields in `--config` as a JSON object (inline, `@file.json`, or `-` for stdin)
so a key does not land in your shell history.

```bash
norbix email integration save --provider Fake
norbix email integration save --provider Sandbox
norbix email integration save --provider SendGrid --name SendGrid --from hello@example.com --config @sendgrid.json
norbix email integration test --integration int_123 --to dev@example.com
norbix email integration confirm-delivery int_123
Expand Down
8 changes: 4 additions & 4 deletions docs/push.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Every command is covered by `tests/push-routes.test.ts`, which runs it through
the real SDK with `fetch` replaced and checks the verb and path it sends (so a
wrong route token fails a test). `tests/push.test.ts` and
`tests/push-existing.test.ts` also check the request fields. No test contacts a
push provider; the only provider a test saves is **Fake**.
push provider; the only provider a test saves is **Sandbox** (API value `Fake`).

All paths below are under `/{version}/notifications/push`.

Expand All @@ -33,15 +33,15 @@ All paths below are under `/{version}/notifications/push`.
| `norbix push integration test --integration <id> [--token <t>] [--family <f>]` | send a test push | `POST /integrations/test` |
| `norbix push integration confirm-delivery <id>` | confirm the test push reached a person | `POST /integrations/confirm-human-delivery` |

`--provider` is one of `Fake`, `AppleApns`, `AndroidFirebase`, `SafariPush`,
`ChromeWeb`, `FirefoxWeb`, `EdgeWeb`, `ChromePush`. **Fake** needs nothing else:
`--provider` is one of `Sandbox`, `AppleApns`, `AndroidFirebase`, `SafariPush`,
`ChromeWeb`, `FirefoxWeb`, `EdgeWeb`, `ChromePush`. **Sandbox** (sent to the API as `Fake`) needs nothing else:
it accepts every send and contacts no push service, so nothing reaches a real
device — use it while you develop. The real providers need their credentials:
put the provider-specific fields in `--config` as a JSON object (inline,
`@file.json`, or `-` for stdin).

```bash
norbix push integration save --provider Fake
norbix push integration save --provider Sandbox
norbix push integration save --provider AndroidFirebase --name Android --config @firebase.json
norbix push integration test --integration int_123 --token dGVzdA== --family Ios
norbix push integration confirm-delivery int_123
Expand Down
10 changes: 5 additions & 5 deletions docs/sms.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Every command is covered by `tests/sms-routes.test.ts`, which runs it through
the real SDK with `fetch` replaced and checks the verb and path it sends (so a
wrong route token fails a test). `tests/sms.test.ts` and
`tests/sms-existing.test.ts` also check the request fields. No test contacts an
SMS provider; the only provider a test saves is **Fake**.
SMS provider; the only provider a test saves is **Sandbox** (API value `Fake`).

All paths below are under `/{version}/notifications/sms`.

Expand Down Expand Up @@ -36,16 +36,16 @@ first two, for scripts that treat every module alike.
| `norbix sms integration test --integration <id> [--to <phone>]` | send a test SMS | `POST /integrations/test` |
| `norbix sms integration confirm-delivery <id>` | confirm the test SMS reached a person | `POST /integrations/confirm-human-delivery` |

`--provider` is one of `Fake`, `Twilio`, `Vonage`, `Plivo`, `Telnyx`, `Bird`,
`Telesign`, `Sinch`. **Fake** needs nothing else: it accepts every send and
`--provider` is one of `Sandbox`, `Twilio`, `Vonage`, `Plivo`, `Telnyx`, `Bird`,
`Telesign`, `Sinch`. **Sandbox** (sent to the API as `Fake`) needs nothing else: it accepts every send and
contacts no SMS service, so nothing reaches a real phone — use it while you
develop. A project can hold one Fake and it has no update path: delete it and
develop. A project can hold one Sandbox and it has no update path: delete it and
add it again. The real providers need their credentials: put the
provider-specific fields in `--config` as a JSON object (inline, `@file.json`,
or `-` for stdin).

```bash
norbix sms integration save --provider Fake
norbix sms integration save --provider Sandbox
norbix sms integration save --provider Twilio --name Twilio --config @twilio.json
norbix sms integration test --integration int_123 --to +37060000000
norbix sms integration confirm-delivery int_123
Expand Down
74 changes: 74 additions & 0 deletions docs/tasks/host-flag-and-sandbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# CLI: --host on hub/api, Fake → Sandbox
This file: /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/docs/tasks/host-flag-and-sandbox.md (branch fix/host-flag)

## Goal
`norbix hub` / `norbix api` honour `--host` (and every other global flag), and the CLI calls the built-in test provider "Sandbox" everywhere a user reads it.
Not in scope: the gateway's enum / API value `Fake`, generated request-field data (src/generated), MCP tool names. Tracking file of the whole batch: /Users/djovaisas/Projects/norbix/worktrees/gateway/fix/small-batch/docs/tasks/small-fixes-batch.md (branch fix/small-batch) — owned by the tracking session.

## Plan
1. [done] fix(cli:hub:host): `hub` and `api` keep --host, --language and --prod as global flags; discovery runs for the --host target — owner item 6
2. [done] feat(cli:integrations:labels): `--provider Sandbox` replaces `--provider Fake` for email / SMS / push; the request still sends `Fake` — owner item 7
3. [doing] release(cli): ship through nbx-ship (rebase merge) and cut a release

## Changes
| file (absolute, branch fix/host-flag) | what changed | step |
|------|--------------|------|
| /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/src/lib/namespace-command.ts | `knownFlags()` derives the global / command flag names; `discoveryArgv()` returns the split global part | 1 |
| /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/src/base.ts | `init()` parses `discoveryArgv()` and gives back the argv oclif overwrote | 1 |
| /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/tests/namespace-host.test.ts | new: two fake gateways ([default] profile host vs --host); 6 tests | 1 |
| /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/src/lib/providers.ts | new: `providerFlag()` — options Sandbox + real providers, Sandbox → `Fake` on the wire | 2 |
| src/commands/{email,sms,push}/integration/{save,test}.ts | help, examples and flag texts say Sandbox | 2 |
| src/commands/code/runs.ts, src/commands/code/marketplace/runs.ts, src/lib/code.ts, src/lib/marketplace.ts | "Fake provider/vendor" → "Sandbox provider/vendor (API value Fake)" | 2 |
| docs/{email,sms,push,code}.md | same rename | 2 |
| tests/{email,sms,push}-routes.test.ts | Sandbox sends `Fake`; `--provider Fake` is refused with a list that names Sandbox | 2 |

## Findings

fix(cli:hub:host): `--host` (also `--language`, `--prod`) was not in the hand-kept global flag list, so it became a request field and the [default] profile host was used — done
where: /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/src/lib/namespace-command.ts:59 (branch fix/host-flag)
```ts
// before — src/lib/namespace-command.ts:39-41 (origin/main 7dc7298)
protected splitArgv(): {flagArgv: string[]; rest: string[]; help: boolean} {
const VALUE_FLAGS = new Set(['--project', '--env', '--region', '--api-key', '--account', '--profile', '--body']) // <-- missing: --host, --language
const BOOL_FLAGS = new Set(['--json', '--yes', '-y', '--dry-run']) // <-- missing: --prod
```
```ts
// after — src/lib/namespace-command.ts:59-61 (fix/host-flag)
protected splitArgv(): {flagArgv: string[]; rest: string[]; help: boolean} {
const ctor = this.constructor as typeof NamespaceCommand
const {VALUE_FLAGS, BOOL_FLAGS} = knownFlags({...BaseCommand.baseFlags, ...ctor.flags})
```

fix(cli:base:discovery): `init()` parsed the full argv of `hub`/`api`, failed on the request fields, swallowed the error and skipped host discovery; and oclif's `parse` overwrites `this.argv` — done
where: /Users/djovaisas/Projects/norbix/worktrees/sdks/cli/fix/host-flag/src/base.ts:370 (branch fix/host-flag)
```ts
// after — src/base.ts:374-384 (fix/host-flag)
let flags: GlobalFlags
// oclif's parse replaces this.argv with what it parsed; `run` needs the whole argv back.
const argv = this.argv
try {
flags = (await this.parse(ctor as unknown as Parameters<typeof this.parse>[0], this.discoveryArgv())).flags as GlobalFlags
} catch {
return
} finally {
this.argv = argv // <-- without this, `hub scheduler tasks get` lost its words and listed the modules
}
```
```ts
// the test that proves it — tests/namespace-host.test.ts:45-51 (fix/host-flag); fails on origin/main, passes here
it('hub <request> --host X goes to X, not to the [default] profile host', async () => {
const r = await cli(home, ['hub', 'scheduler', 'tasks', 'get', ...target(), '--json'])
expect(r.code, r.stderr).toBe(0)
expect(byDefault.hits).toHaveLength(0)
expect(byFlag.hits).toHaveLength(1)
```

## Rejected / moved out
- decision(cli:integrations): keep `Fake` as a hidden alias of `--provider` — rejected — reason: oclif checks `options` before `parse`, so an alias means dropping `options` and `norbix schema` would lose the provider list agents read; Norbix has no tenants yet (greenfield), so no back-compat. `--provider Fake` now fails with "Expected --provider=Fake to be one of: Sandbox, …".
- chore(cli): main checkout /Users/djovaisas/Projects/norbix/sdks/cli is on fix/sdk-1.3-and-deps with 1 changed file — not mine, untouched.

## Needs you
- none

## Open questions
- none
11 changes: 10 additions & 1 deletion src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,15 +372,24 @@ export abstract class BaseCommand extends Command {
const ctor = this.constructor as typeof BaseCommand
if (!ctor.discoversHost) return
let flags: GlobalFlags
// oclif's parse replaces this.argv with what it parsed; `run` needs the whole argv back.
const argv = this.argv
try {
flags = (await this.parse(ctor as unknown as Parameters<typeof this.parse>[0])).flags as GlobalFlags
flags = (await this.parse(ctor as unknown as Parameters<typeof this.parse>[0], this.discoveryArgv())).flags as GlobalFlags
} catch {
return
} finally {
this.argv = argv
}

await this.prepareHost(flags)
}

/** The argv `init` parses to find the host; commands that split their own argv (hub, api) pass the global part only. */
protected discoveryArgv(): string[] {
return this.argv
}

/** Discover the host `flags` point at, so `resolveContext` knows its Hub. */
protected async prepareHost(flags: GlobalFlags, opts: {refresh?: boolean} = {}): Promise<void> {
const target = this.pickTarget(flags)
Expand Down
2 changes: 1 addition & 1 deletion src/commands/code/marketplace/runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const ONE_OF = ['function', 'trigger', 'task', 'connection']
export default class CodeMarketplaceRuns extends BaseCommand {
static description = `The last runs of a marketplace function, of a trigger, of a scheduler task or of an MCP connection's AI tool calls

Newest first: when it ran, the event (invoke for a call by a user, an API key or the AI), the source (user, api-key, ai, database, membership, files, payments, scheduler), the function, the run-as user, the status (ok, failed, skipped), the duration in ms, the error, the vendor's request id and the correlation id. --function lists every run of one function from every source (up to 50 kept); --trigger and --task list the runs that trigger or task started (20 kept). --connection lists the tool calls an AI chat made on an MCP connection without a saved function (each row names the toolName). A run through the Fake vendor also carries input — what the vendor received, secrets masked — printed as JSON under its row (a string with --json).
Newest first: when it ran, the event (invoke for a call by a user, an API key or the AI), the source (user, api-key, ai, database, membership, files, payments, scheduler), the function, the run-as user, the status (ok, failed, skipped), the duration in ms, the error, the vendor's request id and the correlation id. --function lists every run of one function from every source (up to 50 kept); --trigger and --task list the runs that trigger or task started (20 kept). --connection lists the tool calls an AI chat made on an MCP connection without a saved function (each row names the toolName). A run through the Sandbox vendor (API value Fake) also carries input — what the vendor received, secrets masked — printed as JSON under its row (a string with --json).

--details also reads each run's log lines — input, steps, the answer or the error — by its correlation id (GET /logs/audit). They exist only for a run made while the project's logs were on in that environment (hasDetails: true); any other row says "${RUN_DETAILS_NEED_LOGS}". With --json each row gains "details" (the lines, or null) and, when null, "detailsNote".`

Expand Down
2 changes: 1 addition & 1 deletion src/commands/code/runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {formatRuns} from '../../lib/code.js'
export default class CodeRuns extends BaseCommand {
static description = `The last cloud-function runs of a trigger or a scheduler task

Newest first: when it fired, the event, whether it succeeded, the status code, the duration in ms, the error and the provider's request id. A run through the Fake provider also carries input — the envelope the function received, context.runAs.accessToken masked, cut at 64 KB — printed as JSON under its row (a string with --json). The same list as the Last runs panel of the trigger's or task's edit screen.`
Newest first: when it fired, the event, whether it succeeded, the status code, the duration in ms, the error and the provider's request id. A run through the Sandbox provider (API value Fake) also carries input — the envelope the function received, context.runAs.accessToken masked, cut at 64 KB — printed as JSON under its row (a string with --json). The same list as the Last runs panel of the trigger's or task's edit screen.`

static examples = [
'<%= config.bin %> code runs --trigger trg_1p4R3gTobGZpD6fXvHT4rd',
Expand Down
Loading
Loading