@taifoon/n8n-nodes-typesafe 0.1.0 → 1.0.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.
@@ -1,58 +1,21 @@
1
1
  # Key policy and rotation
2
2
 
3
- **Direct connection (the default): one secret.** Your TypeSafe key lives in n8n's encrypted credential store and is sent as a bearer token to `api.typesafe.ai` over TLS. Nobody else is in the path. Rotate it in TypeSafe's console and paste the new value into the credential; that is the whole procedure. Everything below concerns the OPTIONAL Taifoon gateway connection.
3
+ This node uses **one secret: your TypeSafe API key.**
4
4
 
5
- Three secrets exist in the gateway system. This page says where each one lives, who can see it, how it is
6
- rotated, and what happens when one leaks. The node itself holds none of them outside n8n's
7
- encrypted credential store.
5
+ | | |
6
+ |---|---|
7
+ | Where it lives | n8n's credential store, encrypted at rest with your instance's `N8N_ENCRYPTION_KEY` |
8
+ | Where it travels | from your n8n to `api.typesafe.ai`, as a bearer token over TLS. Nobody else is in the path |
9
+ | Where it never goes | workflow JSON, expressions, logs, execution records (HTTP errors are reduced to a status and the service's message, with key-shaped strings redacted, before n8n stores them), or to Taifoon |
8
10
 
9
- | Secret | Owner | Lives | Never |
10
- |---|---|---|---|
11
- | **Taifoon principal key** (`tfn_live_…`) | you | n8n credential store (encrypted at rest with your instance's `N8N_ENCRYPTION_KEY`) | in a workflow JSON, an expression, a log, or git |
12
- | **Your TypeSafe key** | you | n8n credential store; sent per request over TLS in `x-typesafe-key` | stored, logged or echoed by Taifoon. It exists on the deck for the duration of one call |
13
- | **The house TypeSafe key** | Taifoon | the deck's 0600 env file on the production host | sent to any browser, node or client. It funds each principal's three trial calls and nothing else |
11
+ **Rotate** it in TypeSafe's console and paste the new value into the credential. Do it on a schedule
12
+ (90 days is a reasonable default) and at once if a teammate leaves, a screenshot or log may have shown
13
+ it, or a credential test ran on a machine you do not control.
14
14
 
15
- ## What crosses the wire
15
+ **The Free Trial connection uses no secret of yours.** It sends the item and your questions to
16
+ `typesafe.taifoon.dev`, which asks TypeSafe with Taifoon's key: three calls per client, up to 4
17
+ questions and 4,000 characters each. Taifoon logs the outcome, the country and the client type, and a
18
+ salted hash that lets it count clients. It does not log your address, your item or your questions.
19
+ Do not send personal data through the trial; use your own key for real work.
16
20
 
17
- `POST /api/login {key}` exchanges the principal key for an httpOnly, Secure, SameSite=Lax session
18
- cookie valid for 12 hours. n8n caches that session as an expirable token and logs in again when it is
19
- refused. Every later request carries the cookie and, only for `model: "jev"` after the trial, your
20
- TypeSafe key in one header. Responses never contain a key; the deck's log lines (call and billing)
21
- carry latency, tokens, USD and outcome, and never a key or your state.
22
-
23
- ## Rotation
24
-
25
- **Your TypeSafe key.** Rotate it in TypeSafe's console, paste the new value into the n8n credential,
26
- save. Nothing on Taifoon's side needs updating, because Taifoon never stored the old one. Rotate on a
27
- schedule you would use for any vendor key (90 days is a reasonable default) and immediately on any of:
28
- a teammate leaving, a workflow export shared outside your team, a credential test run on a machine
29
- you do not control.
30
-
31
- **Your Taifoon principal key.** Ask the operator to rotate it (`POST /agents/<id>/rotate-key` at the
32
- identity door). The old key stops working at once; existing 12-hour sessions made with it expire on
33
- their own and can be cut short by the operator. Update the n8n credential. Your licence, trial count
34
- and spend ledger are attached to your principal, not to the key string, so they survive rotation.
35
-
36
- **The house key.** Taifoon's to rotate: replace it in the deck's env file and restart the deck. Trial
37
- calls pause for the length of the restart. No user action is needed.
38
-
39
- ## If a key leaks
40
-
41
- | Leaked | Blast radius | Do this |
42
- |---|---|---|
43
- | your TypeSafe key | spend on YOUR TypeSafe quota, by anyone, until rotated | rotate in TypeSafe's console now; review their usage page |
44
- | your Taifoon key | calls billed to your Taifoon key up to its DAILY token ceiling; your three trial calls; read access to the deck as you | ask the operator to rotate; the ceiling bounds the damage per day |
45
- | the house key | Taifoon's TypeSafe quota | Taifoon rotates; trial calls resume after |
46
-
47
- A Taifoon key cannot be used to read anyone's TypeSafe key: the deck has none to read.
48
-
49
- ## Policy the deck enforces, so you do not have to trust the node
50
-
51
- - The first **three** `jev` calls a principal ever makes are funded by Taifoon. The count is per
52
- principal, persisted, and a call that fails upstream is handed back.
53
- - After that, a `jev` call needs **both** the `jev` licence on your principal's grant and your own
54
- TypeSafe key. A missing piece is a `402` that names it. There is no silent fallback to the house key.
55
- - Every call is metered per key **and** per model, persisted across restarts, against a daily ceiling.
56
- - Login throttles: ten refused keys in five minutes from one address rests the door for that window.
57
- - An answer that does not validate is never repaired or defaulted; with **Fail Closed** on (the
58
- default) the node stops the item instead of passing a null downstream.
21
+ Provisioning a key for a team without anyone seeing it: [Supplying keys securely](SECURE_KEYS.md).
@@ -39,8 +39,6 @@ The `_FILE` suffix works on any n8n setting and exists precisely so secrets stay
39
39
  variables, which leak into `docker inspect`, process listings, crash dumps and CI logs. On Kubernetes,
40
40
  mount a `Secret` at the same paths.
41
41
 
42
- For the optional Taifoon gateway the type name is `taifoonGatewayApi`
43
- (`{"taifoonGatewayApi":{"deckUrl":"https://deck.taifoon.dev","principalKey":"…","typesafeKey":"…"}}`).
44
42
 
45
43
  ## 3 · A vault (n8n Enterprise)
46
44
 
@@ -58,9 +56,8 @@ and gain nothing.
58
56
 
59
57
  ## Never send us a key
60
58
 
61
- You do not need to give Taifoon a TypeSafe key, ever. On the direct connection we are not in the path.
62
- On the optional gateway connection your key travels per request over TLS in one header, is used for
63
- that call, and is never stored, logged or echoed. There is deliberately no form, email address or chat
59
+ You do not need to give Taifoon a TypeSafe key, ever. On the direct connection we are not in the path,
60
+ and the free trial uses our key, not yours. There is deliberately no form, email address or chat
64
61
  where we accept keys. If anyone asks you for one in our name, it is not us.
65
62
 
66
63
  If two organisations ever must hand a secret to each other, do it with public-key encryption to the
@@ -49,5 +49,4 @@ threshold on your own labelled items, and leave a question unrouted until you ha
49
49
 
50
50
  With `jev`, state is any JSON up to 96,000 characters: `{{ JSON.stringify($json) }}` sends the whole
51
51
  incoming item. Compute first, judge second: do arithmetic in a Code node and send the result; ask the
52
- model for judgment, never for a sum. House models (`algotrada`, `auditor`) need a flat object of
53
- numbers and short symbols, answer noul and choice only, and return an uncalibrated boolean.
52
+ model for judgment, never for a sum.
package/docs/WORKFLOWS.md CHANGED
@@ -19,12 +19,9 @@ The importable example is `examples/typed-gate.workflow.json`.
19
19
 
20
20
  ## Operating notes
21
21
 
22
- - **Latency.** Jev answers a 4 to 8 question battery in 0.3 to 0.8 s. `auditor` takes about a minute.
23
- The edge cuts any request at 100 s.
22
+ - **Latency.** Jev answers a 4 to 8 question battery in 0.3 to 0.8 s.
24
23
  - **Cost.** About 450 to 550 input tokens per battery, 0.00002 USD on Jev. Output is free.
25
24
  - **Retries.** A `503` means the lane is unavailable and nothing was charged; n8n's *Retry On Fail*
26
25
  with backoff is the right response. A `402` is not retryable: it names what is missing.
27
- - **Observability.** Use **List Lanes** on a schedule to alert on trial exhaustion, spend against the
28
- daily ceiling, and lane health. The deck logs every call and every charge on its own side.
29
26
  - **Batching.** One item is one request. For many items, keep n8n's batching on and the deck's daily
30
27
  ceiling in mind; TypeSafe allows 1,200 requests a minute.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taifoon/n8n-nodes-typesafe",
3
- "version": "0.1.0",
3
+ "version": "1.0.1",
4
4
  "description": "TypeSafe for n8n: ask Jev (a System One model) yes/no, pick-one and rate-it questions about any workflow item and route on calibrated answers. Works directly with your own TypeSafe key; includes a task-to-questions translator and Pass / Fail / Review outputs.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -17,6 +17,7 @@
17
17
  "homepage": "https://github.com/taifoon-io/n8n-nodes-typesafe#readme",
18
18
  "author": {
19
19
  "name": "Taifoon",
20
+ "email": "yawning.monsoon@proton.me",
20
21
  "url": "https://github.com/taifoon-io"
21
22
  },
22
23
  "repository": {
@@ -45,15 +46,14 @@
45
46
  "n8nNodesApiVersion": 1,
46
47
  "strict": true,
47
48
  "credentials": [
48
- "dist/credentials/TypeSafeApi.credentials.js",
49
- "dist/credentials/TaifoonGatewayApi.credentials.js"
49
+ "dist/credentials/TypeSafeApi.credentials.js"
50
50
  ],
51
51
  "nodes": [
52
52
  "dist/nodes/TaifoonTypeSafe/TaifoonTypeSafe.node.js"
53
53
  ]
54
54
  },
55
55
  "devDependencies": {
56
- "@n8n/node-cli": "^0.23.0",
56
+ "@n8n/node-cli": "^0.48.6",
57
57
  "eslint": "^9.39.5",
58
58
  "typescript": "5.9.2"
59
59
  },
@@ -1,13 +0,0 @@
1
- import type { IAuthenticateGeneric, ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IHttpRequestHelper, INodeProperties } from 'n8n-workflow';
2
- export declare class TaifoonGatewayApi implements ICredentialType {
3
- name: string;
4
- displayName: string;
5
- icon: "file:taifoon.svg";
6
- documentationUrl: string;
7
- properties: INodeProperties[];
8
- preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject): Promise<{
9
- sessionToken: string;
10
- }>;
11
- authenticate: IAuthenticateGeneric;
12
- test: ICredentialTestRequest;
13
- }
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TaifoonGatewayApi = void 0;
4
- class TaifoonGatewayApi {
5
- constructor() {
6
- this.name = 'taifoonGatewayApi';
7
- this.displayName = 'Taifoon Gateway API';
8
- this.icon = 'file:taifoon.svg';
9
- this.documentationUrl = 'https://deck.taifoon.dev';
10
- this.properties = [
11
- { displayName: 'Session', name: 'sessionToken', type: 'hidden', typeOptions: { expirable: true, password: true }, default: '' },
12
- { displayName: 'Deck URL', name: 'deckUrl', type: 'string', default: 'https://deck.taifoon.dev', description: 'The Taifoon deck that fronts the typed-decision lanes' },
13
- { displayName: 'Taifoon Principal Key', name: 'principalKey', type: 'string', typeOptions: { password: true }, default: '', required: true, description: 'Your tfn_live_ key. It identifies you, carries your licence and is what usage is billed to.' },
14
- { displayName: 'TypeSafe API Key (Optional)', name: 'typesafeKey', type: 'string', typeOptions: { password: true }, default: '', description: 'Your own key from console.typesafe.ai. Leave empty to use the free trial pings. Needs the jev licence on your Taifoon key.' },
15
- ];
16
- this.authenticate = {
17
- type: 'generic',
18
- properties: { headers: { Cookie: '={{$credentials.sessionToken}}', 'x-typesafe-key': '={{$credentials.typesafeKey || undefined}}' } },
19
- };
20
- this.test = { request: { baseURL: '={{$credentials.deckUrl}}', url: '/api/typed', method: 'GET' } };
21
- }
22
- async preAuthentication(credentials) {
23
- const base = String(credentials.deckUrl || 'https://deck.taifoon.dev').replace(/\/$/, '');
24
- const res = (await this.helpers.httpRequest({ method: 'POST', url: `${base}/api/login`, body: { key: credentials.principalKey }, json: true, returnFullResponse: true }));
25
- const raw = res.headers['set-cookie'];
26
- const cookie = (Array.isArray(raw) ? raw : [String(raw !== null && raw !== void 0 ? raw : '')]).map((c) => String(c).split(';')[0]).filter(Boolean).join('; ');
27
- return { sessionToken: cookie };
28
- }
29
- }
30
- exports.TaifoonGatewayApi = TaifoonGatewayApi;
31
- //# sourceMappingURL=TaifoonGatewayApi.credentials.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TaifoonGatewayApi.credentials.js","sourceRoot":"","sources":["../../credentials/TaifoonGatewayApi.credentials.ts"],"names":[],"mappings":";;;AAgBA,MAAa,iBAAiB;IAA9B;QACC,SAAI,GAAG,mBAAmB,CAAC;QAE3B,gBAAW,GAAG,qBAAqB,CAAC;QAEpC,SAAI,GAAG,kBAA2B,CAAC;QAEnC,qBAAgB,GAAG,0BAA0B,CAAC;QAE9C,eAAU,GAAsB;YAC/B,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/H,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,0BAA0B,EAAE,WAAW,EAAE,uDAAuD,EAAE;YACvK,EAAE,WAAW,EAAE,uBAAuB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6FAA6F,EAAE;YACxP,EAAE,WAAW,EAAE,6BAA6B,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,4HAA4H,EAAE;SAC5Q,CAAC;QAUF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,gBAAgB,EAAE,4CAA4C,EAAE,EAAE;SACrI,CAAC;QAEF,SAAI,GAA2B,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;IACxH,CAAC;IAdA,KAAK,CAAC,iBAAiB,CAA2B,WAA2C;QAC5F,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,IAAI,0BAA0B,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1F,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,WAAW,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAA+D,CAAC;QACxO,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/H,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;IACjC,CAAC;CAQD;AA9BD,8CA8BC"}