@trillboards/cli 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 +1288 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/base-command.d.ts +20 -0
- package/dist/base-command.js +60 -0
- package/dist/commands/api.d.ts +14 -0
- package/dist/commands/api.js +80 -0
- package/dist/commands/audience/live.d.ts +14 -0
- package/dist/commands/audience/live.js +117 -0
- package/dist/commands/billing/usage.d.ts +10 -0
- package/dist/commands/billing/usage.js +92 -0
- package/dist/commands/billing.d.ts +6 -0
- package/dist/commands/billing.js +49 -0
- package/dist/commands/debug.d.ts +10 -0
- package/dist/commands/debug.js +156 -0
- package/dist/commands/doctor.d.ts +6 -0
- package/dist/commands/doctor.js +145 -0
- package/dist/commands/earnings.d.ts +15 -0
- package/dist/commands/earnings.js +182 -0
- package/dist/commands/endpoints/index.d.ts +9 -0
- package/dist/commands/endpoints/index.js +35 -0
- package/dist/commands/errors/index.d.ts +9 -0
- package/dist/commands/errors/index.js +34 -0
- package/dist/commands/fill-rate.d.ts +12 -0
- package/dist/commands/fill-rate.js +141 -0
- package/dist/commands/generated/generated-changelog-query.d.ts +14 -0
- package/dist/commands/generated/generated-changelog-query.js +35 -0
- package/dist/commands/generated/generated-data-api-aggregate.d.ts +15 -0
- package/dist/commands/generated/generated-data-api-aggregate.js +38 -0
- package/dist/commands/generated/generated-data-api-list-screens.d.ts +16 -0
- package/dist/commands/generated/generated-data-api-list-screens.js +41 -0
- package/dist/commands/generated/generated-data-api-lookalike-screens.d.ts +15 -0
- package/dist/commands/generated/generated-data-api-lookalike-screens.js +38 -0
- package/dist/commands/generated/generated-data-api-query-dsl.d.ts +13 -0
- package/dist/commands/generated/generated-data-api-query-dsl.js +32 -0
- package/dist/commands/generated/generated-data-api-screen-audience-history.d.ts +17 -0
- package/dist/commands/generated/generated-data-api-screen-audience-history.js +41 -0
- package/dist/commands/generated/generated-data-api-screen-audience-live.d.ts +14 -0
- package/dist/commands/generated/generated-data-api-screen-audience-live.js +32 -0
- package/dist/commands/generated/generated-data-api-semantic-search.d.ts +16 -0
- package/dist/commands/generated/generated-data-api-semantic-search.js +41 -0
- package/dist/commands/generated/generated-data-api-stats.d.ts +12 -0
- package/dist/commands/generated/generated-data-api-stats.js +26 -0
- package/dist/commands/generated/generated-data-api-stream.d.ts +14 -0
- package/dist/commands/generated/generated-data-api-stream.js +35 -0
- package/dist/commands/generated/generated-data-api-usage.d.ts +13 -0
- package/dist/commands/generated/generated-data-api-usage.js +32 -0
- package/dist/commands/generated/generated-device-ota-manifest.d.ts +13 -0
- package/dist/commands/generated/generated-device-ota-manifest.js +32 -0
- package/dist/commands/generated/generated-example-healthcheck.d.ts +13 -0
- package/dist/commands/generated/generated-example-healthcheck.js +32 -0
- package/dist/commands/generated/generated-playground-dry-run.d.ts +14 -0
- package/dist/commands/generated/generated-playground-dry-run.js +32 -0
- package/dist/commands/generated/generated-request-metadata-get.d.ts +14 -0
- package/dist/commands/generated/generated-request-metadata-get.js +32 -0
- package/dist/commands/generated/generated-sdk-enrich.d.ts +13 -0
- package/dist/commands/generated/generated-sdk-enrich.js +32 -0
- package/dist/commands/generated/generated-sdk-impression.d.ts +13 -0
- package/dist/commands/generated/generated-sdk-impression.js +32 -0
- package/dist/commands/generated/generated-sdk-qr-beacon.d.ts +13 -0
- package/dist/commands/generated/generated-sdk-qr-beacon.js +32 -0
- package/dist/commands/generated/generated-sdk-qr-scan.d.ts +13 -0
- package/dist/commands/generated/generated-sdk-qr-scan.js +32 -0
- package/dist/commands/generated/generated-sensing-paired-training-upload.d.ts +13 -0
- package/dist/commands/generated/generated-sensing-paired-training-upload.js +32 -0
- package/dist/commands/listen.d.ts +39 -0
- package/dist/commands/listen.js +245 -0
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.js +68 -0
- package/dist/commands/logs/tail.d.ts +47 -0
- package/dist/commands/logs/tail.js +240 -0
- package/dist/commands/reconcile.d.ts +9 -0
- package/dist/commands/reconcile.js +58 -0
- package/dist/commands/sandbox/create.d.ts +6 -0
- package/dist/commands/sandbox/create.js +35 -0
- package/dist/commands/sandbox/emit.d.ts +12 -0
- package/dist/commands/sandbox/emit.js +57 -0
- package/dist/commands/sandbox/reset.d.ts +6 -0
- package/dist/commands/sandbox/reset.js +34 -0
- package/dist/commands/sandbox/status.d.ts +6 -0
- package/dist/commands/sandbox/status.js +58 -0
- package/dist/commands/screens/watch.d.ts +14 -0
- package/dist/commands/screens/watch.js +158 -0
- package/dist/commands/trigger.d.ts +9 -0
- package/dist/commands/trigger.js +53 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.js +93 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.js +39 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +32 -0
- package/dist/format-helpers.d.ts +46 -0
- package/dist/format-helpers.js +96 -0
- package/dist/http.d.ts +13 -0
- package/dist/http.js +51 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/output.d.ts +2 -0
- package/dist/output.js +78 -0
- package/oclif.manifest.json +2697 -0
- package/package.json +94 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (partner-api-generated) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Args } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Playgrounddryrun extends BaseCommand {
|
|
8
|
+
static description = "Dry-run validate a request body against an operation schema";
|
|
9
|
+
static examples = [`$ trillboards generated playground-dry-run`];
|
|
10
|
+
static args = {
|
|
11
|
+
operation_id: Args.string({ description: 'The operationId of the endpoint to validate against.', required: true }),
|
|
12
|
+
};
|
|
13
|
+
static flags = {
|
|
14
|
+
...BaseCommand.baseFlags,
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { args, flags } = await this.parse(Playgrounddryrun);
|
|
18
|
+
this.setParsedFlags(flags);
|
|
19
|
+
const apiKey = this.getApiKey();
|
|
20
|
+
if (!apiKey)
|
|
21
|
+
this.error('Not logged in. Run: trillboards login');
|
|
22
|
+
let urlPath = '/v1/playground/{operation_id}';
|
|
23
|
+
urlPath = urlPath.replace('{operation_id}', args['operation_id']);
|
|
24
|
+
const params = {};
|
|
25
|
+
const result = await apiRequest('POST', urlPath, {
|
|
26
|
+
apiKey,
|
|
27
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
28
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Getrequestmetadata extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
request_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (partner-api-generated) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Args } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Getrequestmetadata extends BaseCommand {
|
|
8
|
+
static description = "Look up metadata for a recent API request";
|
|
9
|
+
static examples = [`$ trillboards generated request-metadata get`];
|
|
10
|
+
static args = {
|
|
11
|
+
request_id: Args.string({ description: 'Server-generated request ID to look up.', required: true }),
|
|
12
|
+
};
|
|
13
|
+
static flags = {
|
|
14
|
+
...BaseCommand.baseFlags,
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { args, flags } = await this.parse(Getrequestmetadata);
|
|
18
|
+
this.setParsedFlags(flags);
|
|
19
|
+
const apiKey = this.getApiKey();
|
|
20
|
+
if (!apiKey)
|
|
21
|
+
this.error('Not logged in. Run: trillboards login');
|
|
22
|
+
let urlPath = '/v1/requests/{request_id}';
|
|
23
|
+
urlPath = urlPath.replace('{request_id}', args['request_id']);
|
|
24
|
+
const params = {};
|
|
25
|
+
const result = await apiRequest('GET', urlPath, {
|
|
26
|
+
apiKey,
|
|
27
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
28
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Sdkenrich extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {};
|
|
6
|
+
static flags: {
|
|
7
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sdk-api) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Sdkenrich extends BaseCommand {
|
|
8
|
+
static description = "Census + demographic enrichment from the request IP.";
|
|
9
|
+
static examples = [`$ trillboards generated sdk-enrich`];
|
|
10
|
+
static args = {};
|
|
11
|
+
static flags = {
|
|
12
|
+
...BaseCommand.baseFlags,
|
|
13
|
+
data: Flags.string({ description: 'JSON request body' }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(Sdkenrich);
|
|
17
|
+
this.setParsedFlags(flags);
|
|
18
|
+
const apiKey = this.getApiKey();
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
this.error('Not logged in. Run: trillboards login');
|
|
21
|
+
let urlPath = '/v2/sdk/enrich';
|
|
22
|
+
const params = {};
|
|
23
|
+
const body = flags.data ? JSON.parse(flags.data) : undefined;
|
|
24
|
+
const result = await apiRequest('POST', urlPath, {
|
|
25
|
+
apiKey,
|
|
26
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
27
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
28
|
+
body,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Sdkimpression extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {};
|
|
6
|
+
static flags: {
|
|
7
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sdk-api) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Sdkimpression extends BaseCommand {
|
|
8
|
+
static description = "Ingest an enriched CTV/DOOH impression.";
|
|
9
|
+
static examples = [`$ trillboards generated sdk-impression`];
|
|
10
|
+
static args = {};
|
|
11
|
+
static flags = {
|
|
12
|
+
...BaseCommand.baseFlags,
|
|
13
|
+
data: Flags.string({ description: 'JSON request body' }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(Sdkimpression);
|
|
17
|
+
this.setParsedFlags(flags);
|
|
18
|
+
const apiKey = this.getApiKey();
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
this.error('Not logged in. Run: trillboards login');
|
|
21
|
+
let urlPath = '/v2/sdk/impression';
|
|
22
|
+
const params = {};
|
|
23
|
+
const body = flags.data ? JSON.parse(flags.data) : undefined;
|
|
24
|
+
const result = await apiRequest('POST', urlPath, {
|
|
25
|
+
apiKey,
|
|
26
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
27
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
28
|
+
body,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Sdkqrbeacon extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {};
|
|
6
|
+
static flags: {
|
|
7
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sdk-api) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Sdkqrbeacon extends BaseCommand {
|
|
8
|
+
static description = "Process beacon signals associated with a prior QR scan.";
|
|
9
|
+
static examples = [`$ trillboards generated sdk-qr-beacon`];
|
|
10
|
+
static args = {};
|
|
11
|
+
static flags = {
|
|
12
|
+
...BaseCommand.baseFlags,
|
|
13
|
+
data: Flags.string({ description: 'JSON request body' }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(Sdkqrbeacon);
|
|
17
|
+
this.setParsedFlags(flags);
|
|
18
|
+
const apiKey = this.getApiKey();
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
this.error('Not logged in. Run: trillboards login');
|
|
21
|
+
let urlPath = '/v2/sdk/qr/beacon';
|
|
22
|
+
const params = {};
|
|
23
|
+
const body = flags.data ? JSON.parse(flags.data) : undefined;
|
|
24
|
+
const result = await apiRequest('POST', urlPath, {
|
|
25
|
+
apiKey,
|
|
26
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
27
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
28
|
+
body,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Sdkqrscan extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {};
|
|
6
|
+
static flags: {
|
|
7
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sdk-api) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Sdkqrscan extends BaseCommand {
|
|
8
|
+
static description = "Record a QR-code scan for physical-to-digital attribution.";
|
|
9
|
+
static examples = [`$ trillboards generated sdk-qr-scan`];
|
|
10
|
+
static args = {};
|
|
11
|
+
static flags = {
|
|
12
|
+
...BaseCommand.baseFlags,
|
|
13
|
+
data: Flags.string({ description: 'JSON request body' }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(Sdkqrscan);
|
|
17
|
+
this.setParsedFlags(flags);
|
|
18
|
+
const apiKey = this.getApiKey();
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
this.error('Not logged in. Run: trillboards login');
|
|
21
|
+
let urlPath = '/v2/sdk/qr/scan';
|
|
22
|
+
const params = {};
|
|
23
|
+
const body = flags.data ? JSON.parse(flags.data) : undefined;
|
|
24
|
+
const result = await apiRequest('POST', urlPath, {
|
|
25
|
+
apiKey,
|
|
26
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
27
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
28
|
+
body,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command.js';
|
|
2
|
+
export default class Sensingpairedtrainingupload extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {};
|
|
6
|
+
static flags: {
|
|
7
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// AUTO-GENERATED from OpenAPI spec (sensing-api) -- do not edit manually
|
|
2
|
+
// Regenerate with: npm run generate
|
|
3
|
+
import { Flags } from '@oclif/core';
|
|
4
|
+
import { BaseCommand } from '../../base-command.js';
|
|
5
|
+
import { apiRequest } from '../../http.js';
|
|
6
|
+
import { formatOutput } from '../../output.js';
|
|
7
|
+
export default class Sensingpairedtrainingupload extends BaseCommand {
|
|
8
|
+
static description = "Upload a batch of paired camera/CSI training samples.";
|
|
9
|
+
static examples = [`$ trillboards generated sensing-paired-training-upload`];
|
|
10
|
+
static args = {};
|
|
11
|
+
static flags = {
|
|
12
|
+
...BaseCommand.baseFlags,
|
|
13
|
+
data: Flags.string({ description: 'JSON request body' }),
|
|
14
|
+
};
|
|
15
|
+
async run() {
|
|
16
|
+
const { args, flags } = await this.parse(Sensingpairedtrainingupload);
|
|
17
|
+
this.setParsedFlags(flags);
|
|
18
|
+
const apiKey = this.getApiKey();
|
|
19
|
+
if (!apiKey)
|
|
20
|
+
this.error('Not logged in. Run: trillboards login');
|
|
21
|
+
let urlPath = '/v2/sensing/paired-training-samples';
|
|
22
|
+
const params = {};
|
|
23
|
+
const body = flags.data ? JSON.parse(flags.data) : undefined;
|
|
24
|
+
const result = await apiRequest('POST', urlPath, {
|
|
25
|
+
apiKey,
|
|
26
|
+
baseUrl: flags['base-url'] ?? 'https://api.trillboards.com',
|
|
27
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
28
|
+
body,
|
|
29
|
+
});
|
|
30
|
+
this.log(formatOutput(result, this.getFormat()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { BaseCommand } from '../base-command.js';
|
|
2
|
+
interface SseEnvelope {
|
|
3
|
+
event?: string;
|
|
4
|
+
data: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
}
|
|
7
|
+
export default class Listen extends BaseCommand {
|
|
8
|
+
static args: {
|
|
9
|
+
port: import("@oclif/core/interfaces").Arg<number, {
|
|
10
|
+
max?: number;
|
|
11
|
+
min?: number;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
static description: string;
|
|
15
|
+
static examples: string[];
|
|
16
|
+
static flags: {
|
|
17
|
+
events: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
path: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
};
|
|
20
|
+
private abortController?;
|
|
21
|
+
private reconnectAttempts;
|
|
22
|
+
private secret;
|
|
23
|
+
private shuttingDown;
|
|
24
|
+
run(): Promise<void>;
|
|
25
|
+
/** Compute HMAC-SHA256 hex of the payload with the session secret. */
|
|
26
|
+
static computeSignature(payload: string, secret: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Parse one or more SSE `event:` + `data:` blocks out of a raw buffer.
|
|
29
|
+
* Returns the list of complete envelopes and the remaining unparsed tail.
|
|
30
|
+
*/
|
|
31
|
+
static parseSseBuffer(buffer: string): {
|
|
32
|
+
events: SseEnvelope[];
|
|
33
|
+
remainder: string;
|
|
34
|
+
};
|
|
35
|
+
static sleep(ms: number): Promise<void>;
|
|
36
|
+
private forward;
|
|
37
|
+
private streamOnce;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import { BaseCommand } from '../base-command.js';
|
|
4
|
+
import { colorize } from '../format-helpers.js';
|
|
5
|
+
function maxReconnectAttempts() {
|
|
6
|
+
const raw = process.env.TRILLBOARDS_CLI_MAX_RECONNECTS;
|
|
7
|
+
if (raw === undefined || raw === '')
|
|
8
|
+
return 10;
|
|
9
|
+
const n = Number.parseInt(raw, 10);
|
|
10
|
+
return Number.isFinite(n) ? n : 10;
|
|
11
|
+
}
|
|
12
|
+
function reconnectDelayMs() {
|
|
13
|
+
const raw = process.env.TRILLBOARDS_CLI_RECONNECT_DELAY_MS;
|
|
14
|
+
if (raw === undefined || raw === '')
|
|
15
|
+
return 3000;
|
|
16
|
+
const n = Number.parseInt(raw, 10);
|
|
17
|
+
return Number.isFinite(n) ? n : 3000;
|
|
18
|
+
}
|
|
19
|
+
function forwardTimeoutMs() {
|
|
20
|
+
const raw = process.env.TRILLBOARDS_CLI_FORWARD_TIMEOUT_MS;
|
|
21
|
+
if (raw === undefined || raw === '')
|
|
22
|
+
return 5000;
|
|
23
|
+
const n = Number.parseInt(raw, 10);
|
|
24
|
+
return Number.isFinite(n) ? n : 5000;
|
|
25
|
+
}
|
|
26
|
+
export default class Listen extends BaseCommand {
|
|
27
|
+
static args = {
|
|
28
|
+
port: Args.integer({
|
|
29
|
+
description: 'Local port to forward webhook events to',
|
|
30
|
+
required: true,
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
static description = 'Forward live SSE events to a local HTTP server (webhook dev loop)';
|
|
34
|
+
static examples = [
|
|
35
|
+
'<%= config.bin %> listen 3000',
|
|
36
|
+
'<%= config.bin %> listen 3000 --path /hooks',
|
|
37
|
+
'<%= config.bin %> listen 4000 --events request.logged,error.occurred',
|
|
38
|
+
];
|
|
39
|
+
static flags = {
|
|
40
|
+
events: Flags.string({
|
|
41
|
+
default: '*',
|
|
42
|
+
description: 'Comma-separated SSE event types to subscribe to ("*" = all)',
|
|
43
|
+
}),
|
|
44
|
+
path: Flags.string({
|
|
45
|
+
default: '/webhook',
|
|
46
|
+
description: 'HTTP path on the local server to POST events to',
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
abortController;
|
|
50
|
+
reconnectAttempts = 0;
|
|
51
|
+
secret = '';
|
|
52
|
+
shuttingDown = false;
|
|
53
|
+
async run() {
|
|
54
|
+
const { args, flags } = await this.parse(Listen);
|
|
55
|
+
this.setParsedFlags(flags);
|
|
56
|
+
const apiKey = this.getApiKey();
|
|
57
|
+
if (!apiKey) {
|
|
58
|
+
this.error('Not logged in. Run: trillboards login', { exit: 1 });
|
|
59
|
+
}
|
|
60
|
+
const port = args.port;
|
|
61
|
+
if (!Number.isInteger(port) || port < 1 || port > 65_535) {
|
|
62
|
+
this.error(`Invalid port: ${port}. Must be 1-65535.`, { exit: 1 });
|
|
63
|
+
}
|
|
64
|
+
const baseUrl = this.getBaseUrl();
|
|
65
|
+
const events = flags.events || '*';
|
|
66
|
+
const path = flags.path || '/webhook';
|
|
67
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
68
|
+
// Session-local signing secret — printed for the user to configure verification.
|
|
69
|
+
this.secret = crypto.randomBytes(24).toString('hex');
|
|
70
|
+
this.log(colorize('Trillboards webhook forwarder', 'bold'));
|
|
71
|
+
this.log('');
|
|
72
|
+
this.log(`Forwarding to: ${colorize(`http://localhost:${port}${normalizedPath}`, 'green')}`);
|
|
73
|
+
this.log(`Events: ${events}`);
|
|
74
|
+
this.log('');
|
|
75
|
+
this.log(colorize('Signing secret (use this to verify X-Trillboards-Signature):', 'dim'));
|
|
76
|
+
this.log(` ${this.secret}`);
|
|
77
|
+
this.log('');
|
|
78
|
+
this.log(colorize('Press Ctrl+C to stop', 'dim'));
|
|
79
|
+
this.log('');
|
|
80
|
+
const cleanup = () => {
|
|
81
|
+
this.shuttingDown = true;
|
|
82
|
+
if (this.abortController)
|
|
83
|
+
this.abortController.abort();
|
|
84
|
+
this.log('\nStopped forwarding.');
|
|
85
|
+
process.exit(0);
|
|
86
|
+
};
|
|
87
|
+
process.on('SIGINT', cleanup);
|
|
88
|
+
process.on('SIGTERM', cleanup);
|
|
89
|
+
while (!this.shuttingDown) {
|
|
90
|
+
try {
|
|
91
|
+
await this.streamOnce(apiKey, baseUrl, events, port, normalizedPath);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (this.shuttingDown)
|
|
95
|
+
return;
|
|
96
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
97
|
+
this.log(colorize(`Stream error: ${msg}`, 'red'));
|
|
98
|
+
}
|
|
99
|
+
if (this.shuttingDown)
|
|
100
|
+
return;
|
|
101
|
+
const maxAttempts = maxReconnectAttempts();
|
|
102
|
+
this.reconnectAttempts += 1;
|
|
103
|
+
if (this.reconnectAttempts > maxAttempts) {
|
|
104
|
+
this.error(`Gave up after ${maxAttempts} reconnect attempts.`, { exit: 1 });
|
|
105
|
+
}
|
|
106
|
+
const delayMs = reconnectDelayMs();
|
|
107
|
+
this.log(colorize(`Reconnecting (${this.reconnectAttempts}/${maxAttempts}) in ${delayMs / 1000}s...`, 'yellow'));
|
|
108
|
+
if (delayMs > 0)
|
|
109
|
+
await Listen.sleep(delayMs);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Compute HMAC-SHA256 hex of the payload with the session secret. */
|
|
113
|
+
static computeSignature(payload, secret) {
|
|
114
|
+
return crypto.createHmac('sha256', secret).update(payload).digest('hex');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Parse one or more SSE `event:` + `data:` blocks out of a raw buffer.
|
|
118
|
+
* Returns the list of complete envelopes and the remaining unparsed tail.
|
|
119
|
+
*/
|
|
120
|
+
static parseSseBuffer(buffer) {
|
|
121
|
+
const normalized = buffer.replace(/\r\n/g, '\n');
|
|
122
|
+
const parts = normalized.split('\n\n');
|
|
123
|
+
const remainder = parts.pop() ?? '';
|
|
124
|
+
const out = [];
|
|
125
|
+
for (const chunk of parts) {
|
|
126
|
+
if (!chunk.trim())
|
|
127
|
+
continue;
|
|
128
|
+
const lines = chunk.split('\n').filter((l) => l && !l.startsWith(':'));
|
|
129
|
+
if (lines.length === 0)
|
|
130
|
+
continue;
|
|
131
|
+
let eventType;
|
|
132
|
+
let id;
|
|
133
|
+
const dataLines = [];
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
if (line.startsWith('event:'))
|
|
136
|
+
eventType = line.slice(6).trim();
|
|
137
|
+
else if (line.startsWith('id:'))
|
|
138
|
+
id = line.slice(3).trim();
|
|
139
|
+
else if (line.startsWith('data:'))
|
|
140
|
+
dataLines.push(line.slice(5).trim());
|
|
141
|
+
}
|
|
142
|
+
if (dataLines.length > 0) {
|
|
143
|
+
out.push({ data: dataLines.join('\n'), event: eventType, id });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { events: out, remainder };
|
|
147
|
+
}
|
|
148
|
+
static sleep(ms) {
|
|
149
|
+
return new Promise((resolve) => {
|
|
150
|
+
setTimeout(resolve, ms);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async forward(envelope, port, path) {
|
|
154
|
+
if (!envelope.event || envelope.event === 'connected' || envelope.event === 'disconnected') {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Validate the envelope JSON once. If it's malformed we still forward the
|
|
158
|
+
// raw body so a local server can log and investigate.
|
|
159
|
+
let payloadString = envelope.data;
|
|
160
|
+
try {
|
|
161
|
+
const parsed = JSON.parse(envelope.data);
|
|
162
|
+
payloadString = JSON.stringify(parsed);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// use raw data string as-is
|
|
166
|
+
}
|
|
167
|
+
const signature = Listen.computeSignature(payloadString, this.secret);
|
|
168
|
+
const url = `http://localhost:${port}${path}`;
|
|
169
|
+
const controller = new AbortController();
|
|
170
|
+
const timer = setTimeout(() => controller.abort(), forwardTimeoutMs());
|
|
171
|
+
const started = Date.now();
|
|
172
|
+
try {
|
|
173
|
+
const response = await fetch(url, {
|
|
174
|
+
body: payloadString,
|
|
175
|
+
headers: {
|
|
176
|
+
'Content-Type': 'application/json',
|
|
177
|
+
'X-Trillboards-Event': envelope.event,
|
|
178
|
+
'X-Trillboards-Signature': signature,
|
|
179
|
+
},
|
|
180
|
+
method: 'POST',
|
|
181
|
+
signal: controller.signal,
|
|
182
|
+
});
|
|
183
|
+
const duration = Date.now() - started;
|
|
184
|
+
const status = response.status;
|
|
185
|
+
const color = status >= 500 ? 'red' : status >= 400 ? 'yellow' : 'green';
|
|
186
|
+
this.log(`${colorize(new Date().toISOString(), 'dim')} ${colorize(String(status), color)} POST ${url} ${envelope.event} ${colorize(`${duration}ms`, 'dim')}`);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
190
|
+
const duration = Date.now() - started;
|
|
191
|
+
this.log(`${colorize(new Date().toISOString(), 'dim')} ${colorize('---', 'red')} POST ${url} ${envelope.event} ${colorize(`${duration}ms`, 'dim')} ${colorize(msg, 'red')}`);
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
clearTimeout(timer);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async streamOnce(apiKey, baseUrl, events, port, path) {
|
|
198
|
+
const url = new URL('/v1/partner/events/stream', baseUrl);
|
|
199
|
+
if (events && events !== '*') {
|
|
200
|
+
url.searchParams.set('events', events);
|
|
201
|
+
}
|
|
202
|
+
this.abortController = new AbortController();
|
|
203
|
+
const response = await fetch(url.toString(), {
|
|
204
|
+
headers: {
|
|
205
|
+
'Accept': 'text/event-stream',
|
|
206
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
207
|
+
'User-Agent': 'trillboards-cli',
|
|
208
|
+
'X-Trillboards-Client-Type': 'agent',
|
|
209
|
+
},
|
|
210
|
+
signal: this.abortController.signal,
|
|
211
|
+
});
|
|
212
|
+
if (!response.ok) {
|
|
213
|
+
throw new Error(`Server returned ${response.status} ${response.statusText}`);
|
|
214
|
+
}
|
|
215
|
+
if (!response.body) {
|
|
216
|
+
throw new Error('Server returned an empty body');
|
|
217
|
+
}
|
|
218
|
+
this.reconnectAttempts = 0;
|
|
219
|
+
const reader = response.body.getReader();
|
|
220
|
+
const decoder = new TextDecoder('utf-8');
|
|
221
|
+
let buffer = '';
|
|
222
|
+
try {
|
|
223
|
+
while (!this.shuttingDown) {
|
|
224
|
+
const { done, value } = await reader.read();
|
|
225
|
+
if (done)
|
|
226
|
+
break;
|
|
227
|
+
buffer += decoder.decode(value, { stream: true });
|
|
228
|
+
const { events: parsed, remainder } = Listen.parseSseBuffer(buffer);
|
|
229
|
+
buffer = remainder;
|
|
230
|
+
for (const envelope of parsed) {
|
|
231
|
+
// Fire-and-forget forwarding — don't block the stream read loop
|
|
232
|
+
this.forward(envelope, port, path).catch(() => {
|
|
233
|
+
// forward() already logs errors; swallow here
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
try {
|
|
240
|
+
reader.releaseLock();
|
|
241
|
+
}
|
|
242
|
+
catch { /* ignore */ }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|