palbase 0.3.3 → 0.5.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.
Files changed (60) hide show
  1. package/dist/ai/index.js +10 -13
  2. package/dist/backend/engine.js +2 -2
  3. package/dist/backend/env.js +1 -1
  4. package/dist/backend/index.js +11 -11
  5. package/dist/backend/stack.js +1 -1
  6. package/dist/backend/test.js +2 -2
  7. package/dist/chunks/{4AQYBTIN.js → 2GGJKIKT.js} +2 -2
  8. package/dist/chunks/2S5VK2PA.js +2 -0
  9. package/dist/chunks/{NK54UVDI.js → 6SXSYK4S.js} +2 -2
  10. package/dist/chunks/{IXHR57QC.js → 73WBTWOK.js} +2 -2
  11. package/dist/chunks/{4YD2XCGF.js → ABBUC5HE.js} +1 -1
  12. package/dist/chunks/{PB7UKHCY.js → C627JALV.js} +2 -2
  13. package/dist/chunks/{YWOS5WH2.js → CC36MKWZ.js} +2 -2
  14. package/dist/chunks/{TJ5SQTW5.js → COCND66P.js} +3 -3
  15. package/dist/chunks/{PRM2UXWG.js → FEHN6AHI.js} +1 -1
  16. package/dist/chunks/{P5JIZEPB.js → GUR3A4M7.js} +2 -2
  17. package/dist/chunks/HNMC2RJ7.js +20 -0
  18. package/dist/chunks/{OKZJIY6F.js → IOIQM4QO.js} +1 -1
  19. package/dist/chunks/OROMWNJD.js +6 -0
  20. package/dist/chunks/{47V66C2X.js → R5BCF2YW.js} +2 -2
  21. package/dist/chunks/RBUTW6OM.js +4 -0
  22. package/dist/chunks/{UXRIXHHY.js → RQFK2F3Q.js} +2 -2
  23. package/dist/cli.js +132 -125
  24. package/dist/refuse/ai.js +1 -1
  25. package/dist/refuse/backend.js +1 -1
  26. package/dist/refuse/server.js +1 -1
  27. package/dist/server/index.js +2 -2
  28. package/dist/server/testing.js +2 -2
  29. package/dist/web/index.js +2 -2
  30. package/dist/web/palbe.js +2 -2
  31. package/dist/web/paywall.js +2 -2
  32. package/dist/web/vite.js +2 -2
  33. package/package.json +2 -2
  34. package/types/ai/src/ai.d.ts +63 -2
  35. package/types/ai/src/chats.d.ts +147 -0
  36. package/types/ai/src/index.d.ts +6 -1
  37. package/types/ai/src/tools.d.ts +167 -0
  38. package/types/backend/src/container.d.ts +4 -2
  39. package/types/backend/src/decorators.d.ts +32 -17
  40. package/types/backend/src/engine.d.ts +21 -5
  41. package/types/backend/src/env.d.ts +1 -1
  42. package/types/backend/src/i18n.d.ts +8 -7
  43. package/types/backend/src/index.d.ts +2 -1
  44. package/types/backend/src/strings-files.d.ts +28 -1
  45. package/types/backend/src/tasks.d.ts +168 -0
  46. package/types/internal/src/chat.d.ts +117 -0
  47. package/types/internal/src/modules/auth.d.ts +64 -47
  48. package/types/internal/src/modules/machines.d.ts +320 -79
  49. package/types/internal/src/modules/notify.d.ts +3 -3
  50. package/types/internal/src/modules/purchases.d.ts +562 -3
  51. package/types/internal/src/modules/storage.d.ts +31 -2
  52. package/types/internal/src/tool-output.d.ts +20 -0
  53. package/types/web/src/ai.d.ts +201 -0
  54. package/types/web/src/client.d.ts +10 -0
  55. package/types/web/src/index.d.ts +1 -0
  56. package/types/web/src/paywall/placement.d.ts +2 -0
  57. package/types/web/src/purchases.d.ts +3 -1
  58. package/dist/chunks/CJCMQ73A.js +0 -20
  59. package/dist/chunks/CZQ7KIRM.js +0 -2
  60. package/dist/chunks/M5B52IE6.js +0 -4
@@ -0,0 +1,167 @@
1
+ import type { ai as wire } from '../../internal/src/modules/index.js';
2
+ type AgentDefinition = wire.AgentDefinition;
3
+ type ToolContent = wire.ToolContent;
4
+ type ToolRef = wire.ToolRef;
5
+ import { type ToolResult } from '../../internal/src/tool-output.js';
6
+ import type { Infer, StandardSchema } from './schema.js';
7
+ /** A role, or a catalogue model as provider:model. */
8
+ type Model = 'fast' | 'default' | 'strong' | (string & {});
9
+ /** The chat a tool call or a turn is of, as the platform names it in its signed call. */
10
+ export interface ChatContext {
11
+ /** The chat; '' for a call of a one-shot answer's (ai.ask with tools), which is of no chat. */
12
+ chatId: string;
13
+ /** The agent's name in the chat. */
14
+ agent: string;
15
+ /** The member whose message the turn answers; null: the project's server, or a turn nobody wrote. */
16
+ user: {
17
+ id: string;
18
+ name: string;
19
+ } | null;
20
+ /**
21
+ * The chat's own labels — set by whoever started it, and a user may start
22
+ * one: what they say is the caller's word, not an authority (never a name
23
+ * of something they may then reach).
24
+ */
25
+ metadata: Record<string, string>;
26
+ /** Ended when the platform stops waiting for the answer. */
27
+ signal: AbortSignal;
28
+ }
29
+ export interface ToolContext extends ChatContext {
30
+ /** The call's id: the same call is the same id, whatever copy of the machine it reaches. */
31
+ callId: string;
32
+ }
33
+ export type AgentContext = ChatContext;
34
+ export interface BackendToolOptions<S extends StandardSchema> {
35
+ /** What the agent calls it by: letters, digits, _ and -, starting with a letter, at most 64. */
36
+ name: string;
37
+ /** What it does: the agent reads it to choose. */
38
+ description: string;
39
+ /** What it takes: a zod (valibot, arktype) object schema — the agent is shown it, and its input is checked against it. */
40
+ input: S;
41
+ /**
42
+ * What the call does: a string, an object (said as JSON), pictures
43
+ * (`{ mediaType, bytes }`), or a list of them — 4 MiB at most in all. A
44
+ * throw is the tool's failure: a ToolError's message (or the framework's
45
+ * own refusals', NotFound('…')) is told to the agent, anything else as
46
+ * "The tool failed".
47
+ */
48
+ run(input: Infer<S>, ctx: ToolContext): ToolResult | Promise<ToolResult>;
49
+ /** Every call waits for a person's yes (a member of the chat, or the server). */
50
+ approval?: boolean;
51
+ /** The project's machine it runs on (default backend). */
52
+ machine?: string;
53
+ }
54
+ export interface BackendTool<S extends StandardSchema = StandardSchema> {
55
+ readonly source: 'backend';
56
+ readonly name: string;
57
+ readonly description: string;
58
+ readonly input: S;
59
+ /** The input's JSON Schema, as the agent is shown it. */
60
+ readonly parameters: Record<string, unknown>;
61
+ readonly approval: boolean;
62
+ readonly machine?: string;
63
+ /** The run, its input checked first: what the framework answers the platform's call with. */
64
+ call(input: unknown, ctx: ToolContext): Promise<{
65
+ output: ToolContent[];
66
+ is_error: boolean;
67
+ }>;
68
+ }
69
+ export interface ClientToolOptions<S extends StandardSchema> {
70
+ name: string;
71
+ description: string;
72
+ /** What it takes; none: an empty object. */
73
+ input?: S;
74
+ approval?: boolean;
75
+ }
76
+ /** A tool the app's code answers (pb.ai.chat(id).tools({ name: fn })): the turn waits for its answer. */
77
+ export interface ClientTool {
78
+ readonly source: 'client';
79
+ readonly name: string;
80
+ readonly description: string;
81
+ readonly parameters: Record<string, unknown>;
82
+ readonly approval: boolean;
83
+ }
84
+ /** An HTTPS tool the project put (ai.endpoints.put(name, { kind: 'https', … })). */
85
+ export interface HttpsToolRef {
86
+ source: 'https';
87
+ name: string;
88
+ approval?: boolean;
89
+ }
90
+ /** An MCP server the project put: its tools, or the ones named in only. */
91
+ export interface McpToolRef {
92
+ source: 'mcp';
93
+ name: string;
94
+ only?: string[];
95
+ approval?: boolean;
96
+ }
97
+ export type Tool = BackendTool<StandardSchema> | ClientTool | HttpsToolRef | McpToolRef;
98
+ export interface SubagentDefinition {
99
+ /** Unique among the agent's subagents. */
100
+ name: string;
101
+ /** What it is for: the agent reads it to choose. */
102
+ description: string;
103
+ instructions?: string;
104
+ model?: Model;
105
+ tools?: Tool[];
106
+ /** The turn fails if this subagent's part fails. */
107
+ required?: boolean;
108
+ }
109
+ /** What an agent is for a turn. */
110
+ export interface AgentDefinitionInput {
111
+ instructions?: string;
112
+ model?: Model;
113
+ /** 64 at most, with its MCP servers'. */
114
+ tools?: Tool[];
115
+ /** 16 at most. */
116
+ subagents?: SubagentDefinition[];
117
+ /** How many tool calls a turn makes at most (1–200): past it the agent is told it has no tools left and answers. */
118
+ maxToolCalls?: number;
119
+ /** A named agent's: the app's users start chats with it themselves (when the project lets them). Left out, the server's alone. */
120
+ clients?: boolean;
121
+ }
122
+ /** What a backend's agent is for one turn: whether users reach it is the named agent's, said when it is put. */
123
+ export type TurnDefinition = Omit<AgentDefinitionInput, 'clients'>;
124
+ /** An agent the backend defines at each turn's start: put with ai.agents.put(agent), its chats' turns ask its machine. */
125
+ export interface BackendAgent {
126
+ readonly kind: 'agent';
127
+ readonly name: string;
128
+ /** The project's machine that defines it (default backend). */
129
+ readonly machine?: string;
130
+ /** The app's users start chats with it themselves (put with it). */
131
+ readonly clients: boolean;
132
+ /** The definition for a turn, said as the platform takes it, with the backend tools it hands out. */
133
+ resolve(ctx: AgentContext): Promise<{
134
+ definition: AgentDefinition;
135
+ tools: BackendTool[];
136
+ }>;
137
+ }
138
+ /** What this process declared, for the framework to serve. */
139
+ export interface DeclaredAI {
140
+ tools: Map<string, BackendTool>;
141
+ agents: Map<string, BackendAgent>;
142
+ /** Names declared twice (tool:<name>, agent:<name>): the framework refuses to start with one. */
143
+ twice: Set<string>;
144
+ }
145
+ /**
146
+ * A tool's failure in its own words: thrown from run, its message is what
147
+ * the agent — and the chat's members, who see the call — are told. Any other
148
+ * throw is told as "The tool failed" (a library's or the database's words
149
+ * may name what the chat is not to read); the whole of it is in the app's log.
150
+ */
151
+ export declare class ToolError extends Error {
152
+ constructor(message: string);
153
+ }
154
+ export declare const AGENT_NAME: RegExp;
155
+ /** The input's JSON Schema: an object, written out (no references), as a provider takes a tool's parameters. */
156
+ export declare function parametersOf(schema: StandardSchema | undefined, what: string): Record<string, unknown>;
157
+ export declare function backendTool<S extends StandardSchema>(o: BackendToolOptions<S>): BackendTool<S>;
158
+ export declare function clientTool<S extends StandardSchema>(o: ClientToolOptions<S>): ClientTool;
159
+ export declare function backendAgent(name: string, define: (ctx: AgentContext) => TurnDefinition | Promise<TurnDefinition>, options?: {
160
+ machine?: string;
161
+ clients?: boolean;
162
+ }): BackendAgent;
163
+ /** A tool as the platform takes it (ToolRef). */
164
+ export declare function toolRef(t: Tool, what: string): ToolRef;
165
+ /** A definition as the platform takes it (AgentDefinition). */
166
+ export declare function definitionOf(d: AgentDefinitionInput, what: string): AgentDefinition;
167
+ export {};
@@ -24,8 +24,10 @@ export declare class Container {
24
24
  readonly eventProviders: Ctor[];
25
25
  /** The providers that are @Webhook classes: their @On take a third party's. */
26
26
  readonly webhooks: Ctor[];
27
- /** The providers that are @Job classes: the platform runs them on their schedules. */
28
- readonly jobProviders: Ctor[];
27
+ /** The providers that are @Cron classes: the platform runs them on their schedules. */
28
+ readonly cronProviders: Ctor[];
29
+ /** The providers that are @Task classes: the platform runs them as their tasks come due. */
30
+ readonly taskProviders: Ctor[];
29
31
  /** The providers that are @Room classes. */
30
32
  readonly rooms: Ctor[];
31
33
  constructor(modules: Function[]);
@@ -83,7 +83,8 @@ export declare const INJECTABLE: unique symbol;
83
83
  export declare const MODULE: unique symbol;
84
84
  export declare const EVENTS: unique symbol;
85
85
  export declare const WEBHOOK: unique symbol;
86
- export declare const JOBS: unique symbol;
86
+ export declare const CRONS: unique symbol;
87
+ export declare const TASKS: unique symbol;
87
88
  export declare function declared(): Set<Function>;
88
89
  export declare const RESERVED: Set<string>;
89
90
  export declare function Controller(basePath: string, options?: ControllerOptions): ClassDecorator;
@@ -179,49 +180,63 @@ export declare const isFileEvent: (event: string) => boolean;
179
180
  * offers, and each types its handler (EventHandler).
180
181
  */
181
182
  export declare function On<E extends EventType | (string & {})>(event: E, options?: OnOptions): <F extends EventHandler<E>>(target: object, key: string | symbol, descriptor: TypedPropertyDescriptor<F>) => void;
182
- export interface JobOptions {
183
+ export interface CronOptions {
183
184
  /**
184
185
  * What its runs are kept under (Studio, the CLI) and the platform calls it
185
186
  * by: letters, digits, '.', '_' and '-', at most 64. Renaming it starts a
186
- * new job.
187
+ * new cron.
187
188
  */
188
189
  name: string;
189
- /** Five fields of cron's — minute hour day-of-month month day-of-week — in UTC, like "0 3 * * *". */
190
+ /** Five fields of cron's — minute hour day-of-month month day-of-week — like "0 3 * * *", on the clocks of timeZone. */
190
191
  schedule: string;
191
- /** Seconds one run may take before it is a failed attempt: 1–300 (30). */
192
+ /**
193
+ * The time zone whose clocks the schedule is on, by its IANA name
194
+ * ("Europe/Istanbul", "America/New_York"): UTC when none. Where its clocks
195
+ * change, a time they skip is not run, and a time they show twice is run
196
+ * the first time only.
197
+ */
198
+ timeZone?: string;
199
+ /** Seconds one run may take before it is a failed attempt: 1–900 (30). */
192
200
  timeout?: number;
193
201
  /** Attempts after a failed one, 10 s, 20 s, … five minutes apart: 0–10 (5). */
194
202
  retry?: number;
195
203
  }
196
- export interface JobDeclaration {
204
+ export interface CronDeclaration {
197
205
  name: string;
198
206
  schedule: string;
207
+ timeZone: string;
199
208
  timeout: number;
200
209
  retries: number;
201
210
  }
202
- /** One run of a job, as the platform calls it: what its run(meta) is given. */
203
- export interface JobMeta {
211
+ /** One run of a cron, as the platform calls it: what its run(meta) is given. */
212
+ export interface CronMeta {
204
213
  /** The app's environment variables, as it started (its keys left out). */
205
214
  env: Record<string, string>;
206
215
  /** The project the app belongs to (its id). */
207
216
  environmentId: string;
208
- job: string;
209
- /** The run's id: the same for each attempt of one run — what a job keys its work on to do it once. */
217
+ /** The cron's name. */
218
+ cron: string;
219
+ /** The run's id: the same for each attempt of one run — what a cron keys its work on to do it once. */
210
220
  runId: string;
211
- /** The minute it was due. */
221
+ /** The minute it was due (or was asked to run now). */
212
222
  scheduledAt: Date;
213
223
  /** 1 for the first, then one more each time a failed attempt is made again. */
214
224
  attempt: number;
215
225
  }
226
+ export declare const PLATFORM_NAME: RegExp;
227
+ /** Why a time zone is not one the platform reads its clocks of, or undefined when it is. */
228
+ export declare function zoneProblem(zone: string): string | undefined;
216
229
  /**
217
- * A provider the platform runs on `schedule` — five fields of cron's, in UTC
218
- * — by calling its run(meta), on the machine: woken for it if asleep, one of
219
- * its copies called, one run of a job at a time. A throw is a failed attempt,
220
- * made again; a return is done. It runs in a transaction of its own, as the
230
+ * A provider the platform runs on `schedule` — five fields of cron's, on the
231
+ * clocks of its time zone (UTC unless it names one) — by calling its
232
+ * run(meta), on the machine: woken for it if asleep, one of its copies
233
+ * called, one run of a cron at a time. A throw is a failed attempt, made
234
+ * again; a return is done. It runs in a transaction of its own, as the
221
235
  * service role: no one called it but the app. Off the platform nothing calls
222
- * it. Its module lists it in its providers, as any other.
236
+ * it. Its module lists it in its providers, as any other. Studio and the CLI
237
+ * pause it, resume it and run it now.
223
238
  */
224
- export declare function Job(options: JobOptions): ClassDecorator;
239
+ export declare function Cron(options: CronOptions): ClassDecorator;
225
240
  /** The senders whose signing scheme is known by name. */
226
241
  export type WebhookProvider = 'stripe' | 'github' | 'twilio' | 'sendgrid' | 'slack' | 'discord' | 'livekit';
227
242
  /** A signature scheme spelled out, for a sender with no preset: an HMAC of `signs`, in `header`. */
@@ -1,6 +1,7 @@
1
1
  import { type PalbaseServer, type TokenUser, type TokenVerifier, type WebhookEvent } from '../../server/src/index.js';
2
2
  import { type AuthSpec, type RateLimitConfig } from './decorators.js';
3
3
  import { type ContractOptions } from './openapi.js';
4
+ import { type StringsTable } from './i18n.js';
4
5
  import type { RequestTelemetry } from './requests.js';
5
6
  /** The signed-in user, as @User() gives it. */
6
7
  export interface UserT {
@@ -66,6 +67,12 @@ export interface AppOptions {
66
67
  app: RequestDatabases;
67
68
  requests: 'caller' | 'service';
68
69
  };
70
+ /**
71
+ * The app's strings (palbase/strings/, loadStringsTable): t() answers each request in the first of its
72
+ * Accept-Language's languages the table has, the source language otherwise, and the answer says which
73
+ * (Content-Language) and that it depends on them (Vary: Accept-Language).
74
+ */
75
+ strings?: StringsTable;
69
76
  /**
70
77
  * Built to write its contract and nothing else (PALBASE_CONTRACT_OUT): its
71
78
  * webhooks' secrets are not read, and whether it declares a database says
@@ -84,13 +91,22 @@ export interface AppOptions {
84
91
  * missing_signature, malformed_signature, stale_timestamp or
85
92
  * signature_mismatch. The factory gives it the machine's
86
93
  * PALBASE_PLATFORM_SECRET; unset here, none is served (404). They are:
87
- * - the app's @Job classes: GET /_palbase/jobs lists them (the platform asks
88
- * once a version is up), POST /_palbase/jobs/<name> runs one — its body
89
- * {job, run_id, scheduled_at, attempt} is what the signature covers —
90
- * and answers 204, or the failure the platform tries again;
94
+ * - the app's @Cron classes: GET /_palbase/crons lists them (the platform
95
+ * asks once a version is up), POST /_palbase/crons/<name> runs one — its
96
+ * body {cron, run_id, scheduled_at, attempt} is what the signature covers
97
+ * — and answers 204, or the failure the platform tries again;
98
+ * - its @Task classes: GET /_palbase/tasks lists them (asked with the
99
+ * crons), POST /_palbase/tasks/<name> runs one attempt of a task — {task,
100
+ * id, attempt, payload, created_at} — and answers 204, 422 for a task
101
+ * never to be done (TaskFailure, or a payload its schema refuses), or the
102
+ * failure the platform tries again;
91
103
  * - its @Upload routes' two steps, from storage (upload.ts), and its
92
104
  * @Room classes' joins, messages and moments, from realtime (rooms.ts):
93
- * platform-calls.ts.
105
+ * platform-calls.ts;
106
+ * - its ai tools and agents (@palbase/ai's ai.tool and ai.agent), from the
107
+ * ai module: POST /_palbase/ai/tools runs the tool an agent called (its
108
+ * body's tool), POST /_palbase/ai/agents answers the definition of the
109
+ * agent a turn is of (its body's agent) — ai-calls.ts.
94
110
  */
95
111
  platform?: {
96
112
  secret: string;
@@ -11,7 +11,7 @@ export interface PalbaseConnection {
11
11
  * The key the platform signs its own calls to this machine with —
12
12
  * PALBASE_PLATFORM_SECRET, which the platform starts every machine with.
13
13
  * Off the platform there is none, and what only the platform calls (the
14
- * app's jobs, /_palbase/jobs) is not served.
14
+ * app's crons and tasks, /_palbase/crons and /_palbase/tasks) is not served.
15
15
  */
16
16
  platformSecret?: string;
17
17
  }
@@ -1,14 +1,13 @@
1
- /** The app's strings: its source language, its languages, and each key's cell per language. */
1
+ /**
2
+ * The app's strings (palbase/strings/, loadStringsTable): its source language, the languages it has files for, and
3
+ * each key's translation by language — an empty one is not translated yet, and the key itself answers.
4
+ */
2
5
  export interface StringsTable {
3
- version: 1;
4
6
  source: string;
5
7
  locales: string[];
6
- strings: Record<string, Record<string, {
7
- value: string;
8
- state: 'translated' | 'needs_review' | 'missing';
9
- }>>;
8
+ strings: Record<string, Record<string, string>>;
10
9
  }
11
- /** The languages a request asks for, best first — each tag and then its base language — and the source last. */
10
+ /** The languages a request asks for, best first — each tag, then the shorter ones a table may name — and the source last. */
12
11
  export declare function chainFromAcceptLanguage(header: string | null, source: string | undefined): string[];
13
12
  /** The key's text in the first language of the chain that has it — the key itself in the source language. */
14
13
  export declare function lookup(table: StringsTable, key: string, chain: readonly string[]): {
@@ -17,5 +16,7 @@ export declare function lookup(table: StringsTable, key: string, chain: readonly
17
16
  };
18
17
  /** {{name}} filled from vars ({{{name}}} left as it is); a value not given is empty. */
19
18
  export declare function interpolate(text: string, vars?: Record<string, unknown>): string;
19
+ /** The app started without a table at `root`'s palbase/strings: the first t() says so. */
20
+ export declare function stringsMissingAt(root: string | undefined): void;
20
21
  /** The sentence `key` (written in the source language) in the caller's language, {{name}} filled. */
21
22
  export declare function t(key: string, vars?: Record<string, string | number | boolean | null | undefined>): string;
@@ -1,5 +1,6 @@
1
1
  import 'reflect-metadata';
2
- export { Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers, Injectable, Job, Module, On, OptionalUser, Param, Patch, Post, Put, Query, QueryParams, Req, RequestId, Resolve, TraceId, User, Webhook, type AuthConfig, type AuthSpec, type ControllerOptions, type EventHandler, type JobMeta, type JobOptions, type ModuleDef, type OnOptions, type ParamResolver, type RateLimitConfig, type ResolveContext, type RouteInfo, type RouteOptions, type SignatureSpec, type StandardSchemaV1, type Token, type WebhookOptions, type WebhookProvider, } from './decorators.js';
2
+ export { Body, Client, Controller, Delete, Get, getRegisteredControllers, getRoutes, Headers, Cron, Injectable, Module, On, OptionalUser, Param, Patch, Post, Put, Query, QueryParams, Req, RequestId, Resolve, TraceId, User, Webhook, type AuthConfig, type AuthSpec, type ControllerOptions, type EventHandler, type CronMeta, type CronOptions, type ModuleDef, type OnOptions, type ParamResolver, type RateLimitConfig, type ResolveContext, type RouteInfo, type RouteOptions, type SignatureSpec, type StandardSchemaV1, type Token, type WebhookOptions, type WebhookProvider, } from './decorators.js';
3
+ export { Task, TaskFailure, Tasks, type EnqueueOptions, type PayloadOf, type QueuedTask, type TaskClass, type TaskMeta, type TaskOptions, type TasksService } from './tasks.js';
3
4
  export { Upload, UploadedObject, type UploadConfig } from './upload.js';
4
5
  export { OnAuthorize, OnEmpty, OnFirst, OnJoin, OnLeave, OnMessage, Room, type RoomAuthorizeContext, type RoomContext, type RoomGrant, type RoomMessageContext, type RoomOptions, type RoomUser, } from './rooms.js';
5
6
  export { getWebhookManifest, type WebhookEventHandler, type WebhookMeta } from './webhooks.js';
@@ -1,3 +1,30 @@
1
1
  import type { StringsTable } from './i18n.js';
2
- /** The table under `root` (the app's directory), or undefined when it has none. */
2
+ export declare const STRINGS_DIR = "palbase/strings";
3
+ /** The format this writes and the running app reads. */
4
+ export declare const STRINGS_FORMAT = 3;
5
+ /** A language tag as Intl writes it (en, en-US, zh-Hans): the form a request's languages are matched in. */
6
+ export declare function canonicalLanguage(tag: string): string | undefined;
7
+ /** The files as they are: their format, the source language, and each language's translations by key. */
8
+ export interface StringsFiles {
9
+ format: number;
10
+ source: string;
11
+ languages: Map<string, Map<string, string>>;
12
+ }
13
+ /**
14
+ * palbase/strings/ under `root` read as it is — this format, or the earlier one (its cells' values; a missing one
15
+ * is empty) — every file checked: a file that breaks a rule is named, with the rule. Undefined when there is none.
16
+ */
17
+ export declare function readStringsFiles(root: string, formats?: readonly number[]): Promise<StringsFiles | undefined>;
18
+ /** The table under `root` (the app's directory) the running app answers t() from, or undefined when it has none. */
3
19
  export declare function loadStringsTable(root: string): Promise<StringsTable | undefined>;
20
+ /** One language file's text: its sentences in order, each with its translation, as JSON written for people to edit. */
21
+ export declare function stringsFileText(translations: ReadonlyMap<string, string>, order: readonly string[]): string;
22
+ /**
23
+ * palbase/strings/ under `root` written as `source` and `languages` (each with every key of `order`, in that
24
+ * order), each file written beside itself and renamed into place, a language file no longer in `languages`
25
+ * removed. A run cut short leaves a table the next one reads: a new table's _meta.json is written first (its
26
+ * language files come with it), an existing one's last (a conversion from the earlier format reads the files it
27
+ * already wrote — readStringsFiles takes a plain translation there too). The files whose text changed, by name;
28
+ * a file that differs only in its line endings (a checkout's CRLF) is not one.
29
+ */
30
+ export declare function writeStringsFiles(root: string, source: string, languages: ReadonlyMap<string, ReadonlyMap<string, string>>, order: readonly string[]): Promise<string[]>;
@@ -0,0 +1,168 @@
1
+ import { type StandardSchemaV1 } from './decorators.js';
2
+ export interface TaskOptions {
3
+ /**
4
+ * The task's type: what its tasks are put on the queue under, kept under
5
+ * (Studio, the CLI) and called by — letters, digits, '.', '_' and '-', at
6
+ * most 64.
7
+ */
8
+ name: string;
9
+ /** Seconds one attempt may take before it is a failed one: 1–900 (60). */
10
+ timeout?: number;
11
+ /** Attempts after a failed one, 10 s, 20 s, … an hour apart at most: 0–20 (5). */
12
+ retry?: number;
13
+ /** How many of its tasks the machine runs at once, however many copies it has: 1–50 (5). */
14
+ concurrency?: number;
15
+ /**
16
+ * What a task carries, checked before run() is called: a task that does
17
+ * not hold to it can never be done, and fails at once — it is not tried
18
+ * again. run() is given what the schema gives.
19
+ */
20
+ payload?: StandardSchemaV1;
21
+ }
22
+ export interface TaskDeclaration {
23
+ name: string;
24
+ timeout: number;
25
+ retries: number;
26
+ concurrency: number;
27
+ payload?: StandardSchemaV1;
28
+ }
29
+ /** One attempt of a task, as the platform calls it: what its run(payload, meta) is given beside what it carries. */
30
+ export interface TaskMeta {
31
+ /** The app's environment variables, as it started (its keys left out). */
32
+ env: Record<string, string>;
33
+ /** The project the app belongs to (its id). */
34
+ environmentId: string;
35
+ /** The task's type. */
36
+ task: string;
37
+ /** The task's id: the same for each of its attempts — what it keys its work on to do it once. */
38
+ id: string;
39
+ /** 1 for the first, then one more each time a failed attempt is made again. */
40
+ attempt: number;
41
+ /** When it was put on the queue. */
42
+ createdAt: Date;
43
+ }
44
+ /**
45
+ * Thrown by a task's run(): the task can never be done — what it carries is
46
+ * not what it needs, the thing it works on is gone — and fails now, not to
47
+ * be tried again. Any other throw is an attempt that failed, made again.
48
+ */
49
+ export declare class TaskFailure extends Error {
50
+ constructor(message: string, options?: {
51
+ cause?: unknown;
52
+ });
53
+ }
54
+ /**
55
+ * A provider whose run(payload, meta) does tasks of its type: put on the
56
+ * queue with Tasks.enqueue(TheClass, payload), each run once its time
57
+ * comes — on the platform, which wakes the machine for it; off it, in this
58
+ * process. A return is done; a throw an attempt that failed, made again
59
+ * later (a TaskFailure: failed for good). It runs in a transaction of its
60
+ * own, as the service role: no one called it but the app. Its module lists
61
+ * it in its providers, as any other.
62
+ */
63
+ export declare function Task(options: TaskOptions): ClassDecorator;
64
+ /** A @Task class: its constructor takes what it was written to take, its run() a payload and the meta. */
65
+ export type TaskClass = abstract new (...args: never[]) => {
66
+ run(payload: never, meta: TaskMeta): unknown;
67
+ };
68
+ /** What a @Task class's run() takes as its payload. */
69
+ export type PayloadOf<C> = C extends abstract new (...args: never[]) => {
70
+ run(payload: infer P, ...rest: never[]): unknown;
71
+ } ? P : never;
72
+ export interface EnqueueOptions {
73
+ /** Due this many seconds from now (30 days at most). */
74
+ delay?: number;
75
+ /** Due at this time (30 days from now at most; a time past is now). */
76
+ runAt?: Date;
77
+ /**
78
+ * Put once under this key: another task of its type under the same key,
79
+ * while the first is held — until a day after it is over — is not put,
80
+ * and the first is answered (duplicate: true).
81
+ */
82
+ key?: string;
83
+ }
84
+ /** A task on the queue, as it was put. */
85
+ export interface QueuedTask {
86
+ id: string;
87
+ task: string;
88
+ state: 'waiting' | 'running' | 'succeeded' | 'failed' | 'cancelled';
89
+ attempt: number;
90
+ /** When it is due (RFC 3339): JSON as it is, so a handler can answer with the task. */
91
+ runAt: string;
92
+ key?: string;
93
+ reason?: string;
94
+ /** Put already under its key: this is that task, and nothing new was put. */
95
+ duplicate: boolean;
96
+ }
97
+ /** The queue the app puts its tasks on: the platform's, or its own off the platform. */
98
+ export interface TaskQueue {
99
+ enqueue(task: string, payload: unknown, options: EnqueueOptions & {
100
+ machine?: string;
101
+ }): Promise<QueuedTask>;
102
+ cancel(id: string, machine?: string): Promise<QueuedTask>;
103
+ get(id: string, machine?: string): Promise<QueuedTask>;
104
+ }
105
+ export interface TasksService {
106
+ /**
107
+ * Put a task of this @Task class on the machine's queue, carrying payload
108
+ * — what its run() takes, checked as it is written.
109
+ */
110
+ enqueue<C extends TaskClass>(task: C, payload: PayloadOf<C>, options?: EnqueueOptions): Promise<QueuedTask>;
111
+ /** Put a task of a type by its name — of another of the project's machines, with machine. */
112
+ enqueue(task: string, payload?: unknown, options?: EnqueueOptions & {
113
+ machine?: string;
114
+ }): Promise<QueuedTask>;
115
+ /** Take a task that is waiting off the queue: it is not run. */
116
+ cancel(id: string, options?: {
117
+ machine?: string;
118
+ }): Promise<QueuedTask>;
119
+ /** A task on the queue, as it is now. */
120
+ get(id: string, options?: {
121
+ machine?: string;
122
+ }): Promise<QueuedTask>;
123
+ }
124
+ /** The machine's task queue. */
125
+ export declare const Tasks: TasksService;
126
+ /** The platform's queue of the machine this app runs on (PALBASE_MACHINE), or of another of the project's. */
127
+ export declare function platformQueue(machine: string | undefined): TaskQueue;
128
+ /** How the app does one attempt of a task: what the platform's call would answer. */
129
+ export type RunTask = (call: {
130
+ task: string;
131
+ id: string;
132
+ attempt: number;
133
+ payload: unknown;
134
+ createdAt: Date;
135
+ }, signal: AbortSignal) => Promise<{
136
+ status: number;
137
+ message?: string;
138
+ }>;
139
+ /**
140
+ * The app's own queue, off the platform: its tasks run in this process, as
141
+ * the platform would run them — when due, each type no more at once than its
142
+ * concurrency, an attempt that failed made again later, a key held a day
143
+ * after its task is over. Nothing of it outlives the process.
144
+ */
145
+ export declare class LocalQueue implements TaskQueue {
146
+ private readonly types;
147
+ private readonly run;
148
+ private readonly now;
149
+ private readonly tasks;
150
+ private readonly running;
151
+ private readonly idle;
152
+ constructor(types: ReadonlyMap<string, TaskDeclaration>, run: RunTask, now?: () => number);
153
+ enqueue(task: string, payload: unknown, o: EnqueueOptions & {
154
+ machine?: string;
155
+ }): Promise<QueuedTask>;
156
+ cancel(id: string): Promise<QueuedTask>;
157
+ get(id: string): Promise<QueuedTask>;
158
+ /** Resolves once no task is waiting to run now, nor running: what a test waits for after putting one. */
159
+ settled(): Promise<void>;
160
+ private quiet;
161
+ private known;
162
+ private view;
163
+ private schedule;
164
+ private pump;
165
+ private attempt;
166
+ private finish;
167
+ private wake;
168
+ }