@panter/cloud-tasks 0.0.0-chore-logger-readme-4678c841

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 ADDED
@@ -0,0 +1,221 @@
1
+ # 🚀 Google Cloud Tasks, Simplified
2
+
3
+ A lightweight library that streamlines the use of **Google Cloud Tasks**.
4
+
5
+ ## 🔹 Why Use This Library?
6
+
7
+ Using Google Cloud Tasks typically requires:
8
+
9
+ 1. Implementing a worker service.
10
+ 2. Defining and managing the API between the worker and client.
11
+ 3. Handling task queue management and scheduling.
12
+ 4. Setting up a local development environment.
13
+ 5. Configuring Google Cloud Tasks to send HTTP requests to the worker.
14
+
15
+ This library eliminates much of this complexity by leveraging **tRPC** to define the API between the worker and the client.
16
+
17
+ ### ✅ Key Features
18
+
19
+ - **Seamless API communication** between workers and clients.
20
+ - **Simple task scheduling** with an intuitive API.
21
+ - **Type safety and jump-to-definition** support via tRPC.
22
+ - **Built-in support for local development** with a Cloud Tasks emulator.
23
+
24
+ ---
25
+
26
+ ## 📂 Example Usage
27
+
28
+ Suppose we have one tasks worker (`tasks-worker`) and a backend API (`api`) that will be scheduling tasks.
29
+
30
+ ### Project Structure
31
+
32
+ An example project structure with Turborepo might look like this:
33
+
34
+ ```plaintext
35
+ .
36
+ └── apps/
37
+ ├── tasks-worker/
38
+ │ ├── api.ts
39
+ │ └── index.ts
40
+ └── api/
41
+ └── src/
42
+ └── someEndpoint.ts
43
+ ```
44
+
45
+ > Pro tip: If you have multiple task workers, use naming convention `tasks-worker-<name>`.
46
+
47
+ Two apps that are deployed as two services: `api` and `tasks-worker`.
48
+
49
+ ---
50
+
51
+ ### 🛠 Step 1: Create the Task Worker (`api.ts`)
52
+
53
+ Define a **tRPC-powered task server**:
54
+
55
+ ```ts
56
+ // apps/tasks-worker/api.ts
57
+
58
+ import { logger } from "@repo/logger";
59
+ // yarn add @panter/cloud-tasks
60
+ import { createTasksServer } from "@panter/cloud-tasks/server";
61
+ import { z } from "zod";
62
+
63
+ logger.info("Starting tasks server...");
64
+
65
+ export const { runServer, router } = createTasksServer((t) =>
66
+ t.router({
67
+ createUser: t.procedure
68
+ .input(z.object({ name: z.string().min(5) }))
69
+ .mutation(async (opts) => {
70
+ logger.info(`creating user ${opts.input.name}`);
71
+ }),
72
+ doNothing: t.procedure.mutation(() => {
73
+ logger.info("doing nothing");
74
+ }),
75
+ sendEmail: t.procedure.mutation(() => {
76
+ logger.info("sending email");
77
+ }),
78
+ }),
79
+ );
80
+
81
+ // Export the router type for use in the client
82
+ export type Router = typeof router;
83
+ ```
84
+
85
+ This creates a task server with three tRPC mutations: `createUser`, `doNothing`, and `sendEmail`.
86
+
87
+ Notice that mutations return nothing, as they are called by Google Cloud Tasks and their response is ignored.
88
+
89
+ ---
90
+
91
+ ### 🚀 Step 2: Start the Task Worker (`index.ts`)
92
+
93
+ Initialize the worker server:
94
+
95
+ ```ts
96
+ // apps/tasks-worker/index.ts
97
+
98
+ import { logger } from "@repo/logger";
99
+ import { runServer } from "./api";
100
+
101
+ const port = parseInt(process.env.PORT);
102
+ runServer(port);
103
+ logger.info(`🚀 Task worker tRPC server running at http://localhost:${port}/`);
104
+ ```
105
+
106
+ > Pro tip: Set execution environment for tasks workers to "gen2", deny unauthenticated requests and set higher timeout in catladder:
107
+
108
+ ```ts
109
+ // catladder.ts
110
+
111
+ "tasks-worker": {
112
+ dir: "./apps/tasks-worker",
113
+ deploy: {
114
+ service: {
115
+ allowUnauthenticated: false,
116
+ executionEnvironment: "gen2",
117
+ timeout: "1800s",
118
+ },
119
+ },
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ### 🏗 Step 3: Create the Task Client in `api`
126
+
127
+ Now, in the backend API (`api`), define a **task client** to send tasks:
128
+
129
+ ```ts
130
+ // apps/api/src/someEndpoint.ts
131
+
132
+ import { builder } from "../builder";
133
+ import { logger } from "@repo/logger";
134
+
135
+ // NOTE: we import Router type from the tasks-worker without introducing a runtime dependency
136
+ import type { Router } from "../../tasks-worker-gitlab/api.ts";
137
+ // yarn add @panter/cloud-tasks
138
+ import { createTasksClient } from "@panter/cloud-tasks/client";
139
+
140
+ const tasks = createTasksClient<Router>({
141
+ // TASKS_WORKER_URL is the URL of the task worker service
142
+ tasksWorkerUrl: new URL(process.env.TASKS_WORKER_URL),
143
+ // special characters are not allowed in queue name
144
+ queueName: "reasonable-queue-name",
145
+ // enable emulator in local development
146
+ emulator: process.env.ENV_SHORT === "local" ? { port: 6020 } : false,
147
+ // optional: provide a custom logger
148
+ // assumes `logger.info(metadata, message)` order of arguments (pino logger)
149
+ logger,
150
+ // or provide custom adapter (e.g. for winston logger):
151
+ // logger: {
152
+ // info: (meta, message) => logger.info(message, meta),
153
+ // warn: (meta, message) => logger.warn(message, meta),
154
+ // error: (meta, message) => logger.error(message, meta),
155
+ // },
156
+ });
157
+
158
+ builder.mutationField("runJob", (t) =>
159
+ t.field({
160
+ type: "String",
161
+ resolve: async () => {
162
+ // Schedule a task with a payload
163
+ await tasks.createUser.schedule({ name: "Bilbo Baggins" });
164
+ // ^^^^^^^^^^ Try jumping to definition here!
165
+ return "ok";
166
+ },
167
+ }),
168
+ );
169
+ ```
170
+
171
+ > Pro tip: Set the `TASKS_WORKER_URL` environment variable to the URL of the task worker service in catladder:
172
+
173
+ ```ts
174
+ // catladder.ts
175
+
176
+ api: {
177
+ dir: "./apps/api",
178
+ vars: {
179
+ public: {
180
+ TASKS_WORKER_URL: "${tasks-worker:ROOT_URL_INTERNAL}",
181
+ }
182
+ },
183
+ }
184
+ ```
185
+
186
+ #### 📌 Important: Avoid Circular Dependencies
187
+
188
+ Notice that `Router` is **imported as a type** and by relative path. This makes sure there won't be a circular dependency when e.g. `taks-worker` needs to import `api` to use some business logic.
189
+
190
+ ---
191
+
192
+ ## 🛠 Local Development: Using Cloud Tasks Emulator
193
+
194
+ For local testing, use the **Cloud Tasks Emulator** with Docker:
195
+
196
+ ```yml
197
+ # docker-compose.yml
198
+
199
+ services:
200
+ gcloud-tasks-emulator:
201
+ image: ghcr.io/aertje/cloud-tasks-emulator:latest
202
+ command: -host 0.0.0.0 -port 8123
203
+ ports:
204
+ - "6020:8123"
205
+ # NOTE: Comment out `extra_hosts` if using Podman (see: https://github.com/containers/podman/issues/21681)
206
+ extra_hosts:
207
+ - "host.containers.internal:host-gateway"
208
+ ```
209
+
210
+ ---
211
+
212
+ ## 🎯 Summary
213
+
214
+ This library makes **Google Cloud Tasks** easy to use by:
215
+
216
+ - Removing the need for manual HTTP request handling.
217
+ - Providing a **type-safe, tRPC-powered API**.
218
+ - Enabling seamless communication between workers and clients.
219
+ - Offering **built-in support for local development**.
220
+
221
+ 💡 **With this library, scheduling background tasks is as simple as calling a function!** 🚀
@@ -0,0 +1 @@
1
+ "use strict";var p=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var E=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var i=(o,t)=>p(o,"name",{value:t,configurable:!0});var x=(o,t)=>{for(var e in t)p(o,e,{get:t[e],enumerable:!0})},I=(o,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of E(t))!v.call(o,s)&&s!==e&&p(o,s,{get:()=>t[s],enumerable:!(r=q(t,s))||r.enumerable});return o};var S=o=>I(p({},"__esModule",{value:!0}),o);var L={};x(L,{createTasksClient:()=>O});module.exports=S(L);var f=require("@google-cloud/tasks"),C=require("@grpc/grpc-js"),R=require("google-auth-library"),g=require("google-gax"),a=require("ts-results-es");var h=class{constructor(t,e,r,s){this.client=t;this.location=e;this.queueName=r;this.logger=s;this.projectIdPromise=this.client.getProjectId(),this.serviceAccountEmailPromise=new R.GoogleAuth().getCredentials().then(n=>n.client_email??null)}static{i(this,"CommonTasksClient")}serviceAccountEmailPromise;projectIdPromise;async upsertQueue(t){try{let e=await this.projectIdPromise,r=this.client.queuePath(e,this.location,this.queueName),s=this.client.locationPath(e,this.location);this.logger.info({queuePath:r,parentPath:s},"upserting tasks queue");let n="create";try{await this.client.getQueue({name:r}),n="update"}catch(u){if(k(u)&&u.code===g.Status.NOT_FOUND)n="create";else throw u}return n==="update"?(this.logger.info({queuePath:r},"updating existing queue"),await this.client.updateQueue({queue:{name:r,...t}})):(this.logger.info({queuePath:r},"creating new queue"),await this.client.createQueue({parent:s,queue:{name:r,...t}})),a.Ok.EMPTY}catch(e){return(0,a.Err)(l(e))}}async listTasks(){try{let t=await this.projectIdPromise,e=this.client.queuePath(t,this.location,this.queueName),[r]=await this.client.listTasks({parent:e});return(0,a.Ok)(r)}catch(t){return(0,a.Err)(l(t))}}async createTask(t,e){try{let r=await this.projectIdPromise,s=this.client.queuePath(r,this.location,this.queueName),n=this.client.taskPath(r,this.location,this.queueName,N(t)),u=await this.serviceAccountEmailPromise;return this.logger.info({queuePath:s,taskPath:n,url:e?.httpRequest?.url,payload:e?.httpRequest?.body,serviceAccountEmail:u},"scheduling task"),await this.client.createTask({parent:s,task:{...e,name:n,httpRequest:{...e?.httpRequest,oidcToken:{serviceAccountEmail:u}}}}),(0,a.Ok)(n)}catch(r){return(0,a.Err)(l(r))}}async getTask(t){try{let[e]=await this.client.getTask({name:t});return(0,a.Ok)(e)}catch(e){return k(e)&&e.code===g.Status.NOT_FOUND?(0,a.Ok)(null):(0,a.Err)(l(e))}}},m=class extends h{static{i(this,"RegularTasksClient")}constructor(t,e,r){super(new f.CloudTasksClient({}),t,e,r)}},d=class extends h{static{i(this,"EmulatorTasksClient")}constructor(t,e,r,s){super(new f.CloudTasksClient({sslCreds:C.credentials.createInsecure(),servicePath:s.host??"localhost",port:s.port}),t,e,r)}async upsertQueue(t){try{let e=await this.projectIdPromise,r=this.client.queuePath(e,this.location,this.queueName),s=this.client.locationPath(e,this.location);this.logger.info({queuePath:r,parentPath:s},"upserting simulator tasks queue");try{return await this.client.createQueue({parent:s,queue:{name:r,...t}}),a.Ok.EMPTY}catch(n){return k(n)&&n.code!==g.Status.ALREADY_EXISTS?(0,a.Err)(l(n)):(this.logger.warn({},"dev warning: the queue was not updated due to the emulator not supporting update"),this.logger.warn({},"if you need to update queue options, restart the emulator"),a.Ok.EMPTY)}}catch(e){return(0,a.Err)(l(e))}}async createTask(t,e){return super.createTask(t,{...e,httpRequest:{...e?.httpRequest,url:e?.httpRequest?.url?.replace("//localhost","//host.containers.internal")}})}};function N(o){let t=new Uint8Array(3);crypto.getRandomValues(t);let e=Buffer.from(t).toString("hex");return`${o}-${new Date().getTime()}-${e}`}i(N,"createUniqueName");function k(o){return o instanceof Error&&"code"in o&&Number.isInteger(o.code)}i(k,"isRpcError");function l(o){return k(o)?{...o,type:"rpc"}:{type:"unknown",error:o}}i(l,"toTasksError");function O({queueName:o,emulator:t=!1,location:e="europe-west6",tasksWorkerUrl:r,queueOptions:s,logger:n={error:console.error,info:console.info,warn:console.warn}}){n.info({queueName:o,emulator:t,location:e,tasksWorkerUrl:r},"creating tasks client");let u=t?new d(e,o,n,t):new m(e,o,n);return new Proxy({},{get:i((j,y)=>y==="_manage"?{find:i(c=>u.getTask(c).then(T=>T.unwrap()),"find"),list:i(()=>u.listTasks().then(c=>c.unwrap()),"list")}:{schedule:i(async(c,T)=>{let w=y.toString();await u.upsertQueue(s);let P=new URL(`/trpc/${w}`,r).toString();return n.info({url:P,input:c},"scheduling http request that calls trpc mutation of tasks worker"),(await u.createTask(w,{...T,httpRequest:{httpMethod:"POST",url:P,headers:{"Content-Type":"application/json"},body:c?Buffer.from(JSON.stringify(c)).toString("base64"):null}})).unwrap()},"schedule")},"get")})}i(O,"createTasksClient");
@@ -0,0 +1,58 @@
1
+ import type { google } from "@google-cloud/tasks/build/protos";
2
+ import type { CreateTRPCProxyClient } from "@trpc/client";
3
+ import type { AnyRouter } from "@trpc/server";
4
+ import type { EmulatorConfig, GcpLocation, TaskConfig } from "./tasksClients";
5
+ export declare function createTasksClient<Router extends AnyRouter>({ queueName, emulator, location, tasksWorkerUrl, queueOptions, logger, }: {
6
+ queueName: string;
7
+ location?: GcpLocation;
8
+ queueOptions?: Omit<google.cloud.tasks.v2.IQueue, "name">;
9
+ tasksWorkerUrl: URL;
10
+ logger?: Logger;
11
+ emulator?: false | EmulatorConfig;
12
+ }): ScheduleClient<CreateTRPCProxyClient<Router>>;
13
+ type RemoveNeverKeys<T> = {
14
+ [K in keyof T as T[K] extends never ? never : K]: T[K];
15
+ };
16
+ type OnlyMutate<T> = RemoveNeverKeys<{
17
+ [K in keyof T]: T[K] extends {
18
+ mutate: (...args: infer _A) => unknown;
19
+ } ? T[K] : never;
20
+ }>;
21
+ type ScheduleResult = string;
22
+ type ExtractScheduleFunc<T> = T extends {
23
+ mutate: (...args: infer _A) => unknown;
24
+ } ? (input: Parameters<T["mutate"]>[0], taskConfig?: TaskConfig) => Promise<ScheduleResult> : never;
25
+ type ScheduleClientManage = {
26
+ find: (taskPath: string) => Promise<google.cloud.tasks.v2.ITask | null>;
27
+ list: () => Promise<google.cloud.tasks.v2.ITask[]>;
28
+ };
29
+ /**
30
+ * implementation is in return of `createTasksClient` function
31
+ */
32
+ export type ScheduleClient<T, M = OnlyMutate<T>> = {
33
+ [K in keyof M]: {
34
+ /**
35
+ * Schedule a task with given input.
36
+ * Implementation is in return of `createTasksClient` function.
37
+ *
38
+ * @param input - input for the task
39
+ * @param taskConfig - additional configuration for the task
40
+ *
41
+ * @returns full task path
42
+ * @throws {Error} if task scheduling fails, `cause` property contains details
43
+ */
44
+ schedule: ExtractScheduleFunc<M[K]>;
45
+ };
46
+ } & {
47
+ /**
48
+ * implementation is in return of `createTasksClient` function
49
+ */
50
+ _manage: ScheduleClientManage;
51
+ };
52
+ export type Logger = {
53
+ info: (metadata: Record<string, unknown>, message: string) => void;
54
+ warn: (metadata: Record<string, unknown>, message: string) => void;
55
+ error: (metadata: Record<string, unknown>, message: string) => void;
56
+ };
57
+ export {};
58
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ var C=Object.defineProperty;var a=(o,t)=>C(o,"name",{value:t,configurable:!0});import{CloudTasksClient as P}from"@google-cloud/tasks";import{credentials as R}from"@grpc/grpc-js";import{GoogleAuth as q}from"google-auth-library";import{Status as T}from"google-gax";import{Err as l,Ok as c}from"ts-results-es";var g=class{constructor(t,e,r,n){this.client=t;this.location=e;this.queueName=r;this.logger=n;this.projectIdPromise=this.client.getProjectId(),this.serviceAccountEmailPromise=new q().getCredentials().then(s=>s.client_email??null)}static{a(this,"CommonTasksClient")}serviceAccountEmailPromise;projectIdPromise;async upsertQueue(t){try{let e=await this.projectIdPromise,r=this.client.queuePath(e,this.location,this.queueName),n=this.client.locationPath(e,this.location);this.logger.info({queuePath:r,parentPath:n},"upserting tasks queue");let s="create";try{await this.client.getQueue({name:r}),s="update"}catch(i){if(d(i)&&i.code===T.NOT_FOUND)s="create";else throw i}return s==="update"?(this.logger.info({queuePath:r},"updating existing queue"),await this.client.updateQueue({queue:{name:r,...t}})):(this.logger.info({queuePath:r},"creating new queue"),await this.client.createQueue({parent:n,queue:{name:r,...t}})),c.EMPTY}catch(e){return l(p(e))}}async listTasks(){try{let t=await this.projectIdPromise,e=this.client.queuePath(t,this.location,this.queueName),[r]=await this.client.listTasks({parent:e});return c(r)}catch(t){return l(p(t))}}async createTask(t,e){try{let r=await this.projectIdPromise,n=this.client.queuePath(r,this.location,this.queueName),s=this.client.taskPath(r,this.location,this.queueName,E(t)),i=await this.serviceAccountEmailPromise;return this.logger.info({queuePath:n,taskPath:s,url:e?.httpRequest?.url,payload:e?.httpRequest?.body,serviceAccountEmail:i},"scheduling task"),await this.client.createTask({parent:n,task:{...e,name:s,httpRequest:{...e?.httpRequest,oidcToken:{serviceAccountEmail:i}}}}),c(s)}catch(r){return l(p(r))}}async getTask(t){try{let[e]=await this.client.getTask({name:t});return c(e)}catch(e){return d(e)&&e.code===T.NOT_FOUND?c(null):l(p(e))}}},h=class extends g{static{a(this,"RegularTasksClient")}constructor(t,e,r){super(new P({}),t,e,r)}},m=class extends g{static{a(this,"EmulatorTasksClient")}constructor(t,e,r,n){super(new P({sslCreds:R.createInsecure(),servicePath:n.host??"localhost",port:n.port}),t,e,r)}async upsertQueue(t){try{let e=await this.projectIdPromise,r=this.client.queuePath(e,this.location,this.queueName),n=this.client.locationPath(e,this.location);this.logger.info({queuePath:r,parentPath:n},"upserting simulator tasks queue");try{return await this.client.createQueue({parent:n,queue:{name:r,...t}}),c.EMPTY}catch(s){return d(s)&&s.code!==T.ALREADY_EXISTS?l(p(s)):(this.logger.warn({},"dev warning: the queue was not updated due to the emulator not supporting update"),this.logger.warn({},"if you need to update queue options, restart the emulator"),c.EMPTY)}}catch(e){return l(p(e))}}async createTask(t,e){return super.createTask(t,{...e,httpRequest:{...e?.httpRequest,url:e?.httpRequest?.url?.replace("//localhost","//host.containers.internal")}})}};function E(o){let t=new Uint8Array(3);crypto.getRandomValues(t);let e=Buffer.from(t).toString("hex");return`${o}-${new Date().getTime()}-${e}`}a(E,"createUniqueName");function d(o){return o instanceof Error&&"code"in o&&Number.isInteger(o.code)}a(d,"isRpcError");function p(o){return d(o)?{...o,type:"rpc"}:{type:"unknown",error:o}}a(p,"toTasksError");function K({queueName:o,emulator:t=!1,location:e="europe-west6",tasksWorkerUrl:r,queueOptions:n,logger:s={error:console.error,info:console.info,warn:console.warn}}){s.info({queueName:o,emulator:t,location:e,tasksWorkerUrl:r},"creating tasks client");let i=t?new m(e,o,s,t):new h(e,o,s);return new Proxy({},{get:a((v,f)=>f==="_manage"?{find:a(u=>i.getTask(u).then(k=>k.unwrap()),"find"),list:a(()=>i.listTasks().then(u=>u.unwrap()),"list")}:{schedule:a(async(u,k)=>{let y=f.toString();await i.upsertQueue(n);let w=new URL(`/trpc/${y}`,r).toString();return s.info({url:w,input:u},"scheduling http request that calls trpc mutation of tasks worker"),(await i.createTask(y,{...k,httpRequest:{httpMethod:"POST",url:w,headers:{"Content-Type":"application/json"},body:u?Buffer.from(JSON.stringify(u)).toString("base64"):null}})).unwrap()},"schedule")},"get")})}a(K,"createTasksClient");export{K as createTasksClient};
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var I=Object.create;var p=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,L=Object.prototype.hasOwnProperty;var a=(r,t)=>p(r,"name",{value:t,configurable:!0});var A=(r,t)=>{for(var e in t)p(r,e,{get:t[e],enumerable:!0})},R=(r,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of N(t))!L.call(r,s)&&s!==e&&p(r,s,{get:()=>t[s],enumerable:!(o=S(t,s))||o.enumerable});return r};var M=(r,t,e)=>(e=r!=null?I(O(r)):{},R(t||!r||!r.__esModule?p(e,"default",{value:r,enumerable:!0}):e,r)),j=r=>R(p({},"__esModule",{value:!0}),r);var _={};A(_,{createTasksClient:()=>K,createTasksServer:()=>b});module.exports=j(_);var T=require("@google-cloud/tasks"),C=require("@grpc/grpc-js"),q=require("google-auth-library"),g=require("google-gax"),i=require("ts-results-es");var m=class{constructor(t,e,o,s){this.client=t;this.location=e;this.queueName=o;this.logger=s;this.projectIdPromise=this.client.getProjectId(),this.serviceAccountEmailPromise=new q.GoogleAuth().getCredentials().then(n=>n.client_email??null)}static{a(this,"CommonTasksClient")}serviceAccountEmailPromise;projectIdPromise;async upsertQueue(t){try{let e=await this.projectIdPromise,o=this.client.queuePath(e,this.location,this.queueName),s=this.client.locationPath(e,this.location);this.logger.info({queuePath:o,parentPath:s},"upserting tasks queue");let n="create";try{await this.client.getQueue({name:o}),n="update"}catch(u){if(k(u)&&u.code===g.Status.NOT_FOUND)n="create";else throw u}return n==="update"?(this.logger.info({queuePath:o},"updating existing queue"),await this.client.updateQueue({queue:{name:o,...t}})):(this.logger.info({queuePath:o},"creating new queue"),await this.client.createQueue({parent:s,queue:{name:o,...t}})),i.Ok.EMPTY}catch(e){return(0,i.Err)(l(e))}}async listTasks(){try{let t=await this.projectIdPromise,e=this.client.queuePath(t,this.location,this.queueName),[o]=await this.client.listTasks({parent:e});return(0,i.Ok)(o)}catch(t){return(0,i.Err)(l(t))}}async createTask(t,e){try{let o=await this.projectIdPromise,s=this.client.queuePath(o,this.location,this.queueName),n=this.client.taskPath(o,this.location,this.queueName,Q(t)),u=await this.serviceAccountEmailPromise;return this.logger.info({queuePath:s,taskPath:n,url:e?.httpRequest?.url,payload:e?.httpRequest?.body,serviceAccountEmail:u},"scheduling task"),await this.client.createTask({parent:s,task:{...e,name:n,httpRequest:{...e?.httpRequest,oidcToken:{serviceAccountEmail:u}}}}),(0,i.Ok)(n)}catch(o){return(0,i.Err)(l(o))}}async getTask(t){try{let[e]=await this.client.getTask({name:t});return(0,i.Ok)(e)}catch(e){return k(e)&&e.code===g.Status.NOT_FOUND?(0,i.Ok)(null):(0,i.Err)(l(e))}}},h=class extends m{static{a(this,"RegularTasksClient")}constructor(t,e,o){super(new T.CloudTasksClient({}),t,e,o)}},d=class extends m{static{a(this,"EmulatorTasksClient")}constructor(t,e,o,s){super(new T.CloudTasksClient({sslCreds:C.credentials.createInsecure(),servicePath:s.host??"localhost",port:s.port}),t,e,o)}async upsertQueue(t){try{let e=await this.projectIdPromise,o=this.client.queuePath(e,this.location,this.queueName),s=this.client.locationPath(e,this.location);this.logger.info({queuePath:o,parentPath:s},"upserting simulator tasks queue");try{return await this.client.createQueue({parent:s,queue:{name:o,...t}}),i.Ok.EMPTY}catch(n){return k(n)&&n.code!==g.Status.ALREADY_EXISTS?(0,i.Err)(l(n)):(this.logger.warn({},"dev warning: the queue was not updated due to the emulator not supporting update"),this.logger.warn({},"if you need to update queue options, restart the emulator"),i.Ok.EMPTY)}}catch(e){return(0,i.Err)(l(e))}}async createTask(t,e){return super.createTask(t,{...e,httpRequest:{...e?.httpRequest,url:e?.httpRequest?.url?.replace("//localhost","//host.containers.internal")}})}};function Q(r){let t=new Uint8Array(3);crypto.getRandomValues(t);let e=Buffer.from(t).toString("hex");return`${r}-${new Date().getTime()}-${e}`}a(Q,"createUniqueName");function k(r){return r instanceof Error&&"code"in r&&Number.isInteger(r.code)}a(k,"isRpcError");function l(r){return k(r)?{...r,type:"rpc"}:{type:"unknown",error:r}}a(l,"toTasksError");function K({queueName:r,emulator:t=!1,location:e="europe-west6",tasksWorkerUrl:o,queueOptions:s,logger:n={error:console.error,info:console.info,warn:console.warn}}){n.info({queueName:r,emulator:t,location:e,tasksWorkerUrl:o},"creating tasks client");let u=t?new d(e,r,n,t):new h(e,r,n);return new Proxy({},{get:a((U,y)=>y==="_manage"?{find:a(c=>u.getTask(c).then(f=>f.unwrap()),"find"),list:a(()=>u.listTasks().then(c=>c.unwrap()),"list")}:{schedule:a(async(c,f)=>{let w=y.toString();await u.upsertQueue(s);let P=new URL(`/trpc/${w}`,o).toString();return n.info({url:P,input:c},"scheduling http request that calls trpc mutation of tasks worker"),(await u.createTask(w,{...f,httpRequest:{httpMethod:"POST",url:P,headers:{"Content-Type":"application/json"},body:c?Buffer.from(JSON.stringify(c)).toString("base64"):null}})).unwrap()},"schedule")},"get")})}a(K,"createTasksClient");var v=require("@trpc/server"),E=require("@trpc/server/adapters/express"),x=M(require("express"));function b(r){let t=v.initTRPC.create(),e=r(t),o=(0,x.default)();return o.use("/trpc",(0,E.createExpressMiddleware)({router:e})),{runServer:a(s=>{o.listen({port:s})},"runServer"),router:e}}a(b,"createTasksServer");
@@ -0,0 +1,3 @@
1
+ export * from "./client";
2
+ export * from "./server";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ var R=Object.defineProperty;var a=(o,t)=>R(o,"name",{value:t,configurable:!0});import{CloudTasksClient as P}from"@google-cloud/tasks";import{credentials as C}from"@grpc/grpc-js";import{GoogleAuth as q}from"google-auth-library";import{Status as f}from"google-gax";import{Err as l,Ok as c}from"ts-results-es";var g=class{constructor(t,e,r,n){this.client=t;this.location=e;this.queueName=r;this.logger=n;this.projectIdPromise=this.client.getProjectId(),this.serviceAccountEmailPromise=new q().getCredentials().then(s=>s.client_email??null)}static{a(this,"CommonTasksClient")}serviceAccountEmailPromise;projectIdPromise;async upsertQueue(t){try{let e=await this.projectIdPromise,r=this.client.queuePath(e,this.location,this.queueName),n=this.client.locationPath(e,this.location);this.logger.info({queuePath:r,parentPath:n},"upserting tasks queue");let s="create";try{await this.client.getQueue({name:r}),s="update"}catch(i){if(d(i)&&i.code===f.NOT_FOUND)s="create";else throw i}return s==="update"?(this.logger.info({queuePath:r},"updating existing queue"),await this.client.updateQueue({queue:{name:r,...t}})):(this.logger.info({queuePath:r},"creating new queue"),await this.client.createQueue({parent:n,queue:{name:r,...t}})),c.EMPTY}catch(e){return l(p(e))}}async listTasks(){try{let t=await this.projectIdPromise,e=this.client.queuePath(t,this.location,this.queueName),[r]=await this.client.listTasks({parent:e});return c(r)}catch(t){return l(p(t))}}async createTask(t,e){try{let r=await this.projectIdPromise,n=this.client.queuePath(r,this.location,this.queueName),s=this.client.taskPath(r,this.location,this.queueName,v(t)),i=await this.serviceAccountEmailPromise;return this.logger.info({queuePath:n,taskPath:s,url:e?.httpRequest?.url,payload:e?.httpRequest?.body,serviceAccountEmail:i},"scheduling task"),await this.client.createTask({parent:n,task:{...e,name:s,httpRequest:{...e?.httpRequest,oidcToken:{serviceAccountEmail:i}}}}),c(s)}catch(r){return l(p(r))}}async getTask(t){try{let[e]=await this.client.getTask({name:t});return c(e)}catch(e){return d(e)&&e.code===f.NOT_FOUND?c(null):l(p(e))}}},m=class extends g{static{a(this,"RegularTasksClient")}constructor(t,e,r){super(new P({}),t,e,r)}},h=class extends g{static{a(this,"EmulatorTasksClient")}constructor(t,e,r,n){super(new P({sslCreds:C.createInsecure(),servicePath:n.host??"localhost",port:n.port}),t,e,r)}async upsertQueue(t){try{let e=await this.projectIdPromise,r=this.client.queuePath(e,this.location,this.queueName),n=this.client.locationPath(e,this.location);this.logger.info({queuePath:r,parentPath:n},"upserting simulator tasks queue");try{return await this.client.createQueue({parent:n,queue:{name:r,...t}}),c.EMPTY}catch(s){return d(s)&&s.code!==f.ALREADY_EXISTS?l(p(s)):(this.logger.warn({},"dev warning: the queue was not updated due to the emulator not supporting update"),this.logger.warn({},"if you need to update queue options, restart the emulator"),c.EMPTY)}}catch(e){return l(p(e))}}async createTask(t,e){return super.createTask(t,{...e,httpRequest:{...e?.httpRequest,url:e?.httpRequest?.url?.replace("//localhost","//host.containers.internal")}})}};function v(o){let t=new Uint8Array(3);crypto.getRandomValues(t);let e=Buffer.from(t).toString("hex");return`${o}-${new Date().getTime()}-${e}`}a(v,"createUniqueName");function d(o){return o instanceof Error&&"code"in o&&Number.isInteger(o.code)}a(d,"isRpcError");function p(o){return d(o)?{...o,type:"rpc"}:{type:"unknown",error:o}}a(p,"toTasksError");function U({queueName:o,emulator:t=!1,location:e="europe-west6",tasksWorkerUrl:r,queueOptions:n,logger:s={error:console.error,info:console.info,warn:console.warn}}){s.info({queueName:o,emulator:t,location:e,tasksWorkerUrl:r},"creating tasks client");let i=t?new h(e,o,s,t):new m(e,o,s);return new Proxy({},{get:a((S,T)=>T==="_manage"?{find:a(u=>i.getTask(u).then(k=>k.unwrap()),"find"),list:a(()=>i.listTasks().then(u=>u.unwrap()),"list")}:{schedule:a(async(u,k)=>{let y=T.toString();await i.upsertQueue(n);let w=new URL(`/trpc/${y}`,r).toString();return s.info({url:w,input:u},"scheduling http request that calls trpc mutation of tasks worker"),(await i.createTask(y,{...k,httpRequest:{httpMethod:"POST",url:w,headers:{"Content-Type":"application/json"},body:u?Buffer.from(JSON.stringify(u)).toString("base64"):null}})).unwrap()},"schedule")},"get")})}a(U,"createTasksClient");import{initTRPC as E}from"@trpc/server";import{createExpressMiddleware as x}from"@trpc/server/adapters/express";import I from"express";function B(o){let t=E.create(),e=o(t),r=I();return r.use("/trpc",x({router:e})),{runServer:a(n=>{r.listen({port:n})},"runServer"),router:e}}a(B,"createTasksServer");export{U as createTasksClient,B as createTasksServer};
@@ -0,0 +1 @@
1
+ "use strict";var a=Object.create;var p=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,x=Object.prototype.hasOwnProperty;var s=(e,r)=>p(e,"name",{value:r,configurable:!0});var T=(e,r)=>{for(var t in r)p(e,t,{get:r[t],enumerable:!0})},i=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of f(r))!x.call(e,o)&&o!==t&&p(e,o,{get:()=>r[o],enumerable:!(n=R(r,o))||n.enumerable});return e};var d=(e,r,t)=>(t=e!=null?a(y(e)):{},i(r||!e||!e.__esModule?p(t,"default",{value:e,enumerable:!0}):t,e)),v=e=>i(p({},"__esModule",{value:!0}),e);var A={};T(A,{createTasksServer:()=>l});module.exports=v(A);var u=require("@trpc/server"),c=require("@trpc/server/adapters/express"),m=d(require("express"));function l(e){let r=u.initTRPC.create(),t=e(r),n=(0,m.default)();return n.use("/trpc",(0,c.createExpressMiddleware)({router:t})),{runServer:s(o=>{n.listen({port:o})},"runServer"),router:t}}s(l,"createTasksServer");
@@ -0,0 +1,7 @@
1
+ import type { AnyRouter } from "@trpc/server";
2
+ import { initTRPC } from "@trpc/server";
3
+ export declare function createTasksServer<Router extends AnyRouter>(createRouter: (t: ReturnType<(typeof initTRPC)["create"]>) => Router): {
4
+ runServer: (port: number) => void;
5
+ router: Router;
6
+ };
7
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAIxC,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,SAAS,EACxD,YAAY,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,MAAM;sBAShD,MAAM;;EAK3B"}
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var t=(e,r)=>s(e,"name",{value:r,configurable:!0});import{initTRPC as i}from"@trpc/server";import{createExpressMiddleware as u}from"@trpc/server/adapters/express";import c from"express";function y(e){let r=i.create(),o=e(r),n=c();return n.use("/trpc",u({router:o})),{runServer:t(p=>{n.listen({port:p})},"runServer"),router:o}}t(y,"createTasksServer");export{y as createTasksServer};
@@ -0,0 +1 @@
1
+ "use strict";var l=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var i=(o,e)=>l(o,"name",{value:e,configurable:!0});var q=(o,e)=>{for(var t in e)l(o,t,{get:e[t],enumerable:!0})},E=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of f(e))!w.call(o,s)&&s!==t&&l(o,s,{get:()=>e[s],enumerable:!(r=T(e,s))||r.enumerable});return o};var I=o=>E(l({},"__esModule",{value:!0}),o);var v={};q(v,{EmulatorTasksClient:()=>d,RegularTasksClient:()=>m});module.exports=I(v);var k=require("@google-cloud/tasks"),y=require("@grpc/grpc-js"),P=require("google-auth-library"),p=require("google-gax"),n=require("ts-results-es");var h=class{constructor(e,t,r,s){this.client=e;this.location=t;this.queueName=r;this.logger=s;this.projectIdPromise=this.client.getProjectId(),this.serviceAccountEmailPromise=new P.GoogleAuth().getCredentials().then(a=>a.client_email??null)}static{i(this,"CommonTasksClient")}serviceAccountEmailPromise;projectIdPromise;async upsertQueue(e){try{let t=await this.projectIdPromise,r=this.client.queuePath(t,this.location,this.queueName),s=this.client.locationPath(t,this.location);this.logger.info({queuePath:r,parentPath:s},"upserting tasks queue");let a="create";try{await this.client.getQueue({name:r}),a="update"}catch(u){if(g(u)&&u.code===p.Status.NOT_FOUND)a="create";else throw u}return a==="update"?(this.logger.info({queuePath:r},"updating existing queue"),await this.client.updateQueue({queue:{name:r,...e}})):(this.logger.info({queuePath:r},"creating new queue"),await this.client.createQueue({parent:s,queue:{name:r,...e}})),n.Ok.EMPTY}catch(t){return(0,n.Err)(c(t))}}async listTasks(){try{let e=await this.projectIdPromise,t=this.client.queuePath(e,this.location,this.queueName),[r]=await this.client.listTasks({parent:t});return(0,n.Ok)(r)}catch(e){return(0,n.Err)(c(e))}}async createTask(e,t){try{let r=await this.projectIdPromise,s=this.client.queuePath(r,this.location,this.queueName),a=this.client.taskPath(r,this.location,this.queueName,R(e)),u=await this.serviceAccountEmailPromise;return this.logger.info({queuePath:s,taskPath:a,url:t?.httpRequest?.url,payload:t?.httpRequest?.body,serviceAccountEmail:u},"scheduling task"),await this.client.createTask({parent:s,task:{...t,name:a,httpRequest:{...t?.httpRequest,oidcToken:{serviceAccountEmail:u}}}}),(0,n.Ok)(a)}catch(r){return(0,n.Err)(c(r))}}async getTask(e){try{let[t]=await this.client.getTask({name:e});return(0,n.Ok)(t)}catch(t){return g(t)&&t.code===p.Status.NOT_FOUND?(0,n.Ok)(null):(0,n.Err)(c(t))}}},m=class extends h{static{i(this,"RegularTasksClient")}constructor(e,t,r){super(new k.CloudTasksClient({}),e,t,r)}},d=class extends h{static{i(this,"EmulatorTasksClient")}constructor(e,t,r,s){super(new k.CloudTasksClient({sslCreds:y.credentials.createInsecure(),servicePath:s.host??"localhost",port:s.port}),e,t,r)}async upsertQueue(e){try{let t=await this.projectIdPromise,r=this.client.queuePath(t,this.location,this.queueName),s=this.client.locationPath(t,this.location);this.logger.info({queuePath:r,parentPath:s},"upserting simulator tasks queue");try{return await this.client.createQueue({parent:s,queue:{name:r,...e}}),n.Ok.EMPTY}catch(a){return g(a)&&a.code!==p.Status.ALREADY_EXISTS?(0,n.Err)(c(a)):(this.logger.warn({},"dev warning: the queue was not updated due to the emulator not supporting update"),this.logger.warn({},"if you need to update queue options, restart the emulator"),n.Ok.EMPTY)}}catch(t){return(0,n.Err)(c(t))}}async createTask(e,t){return super.createTask(e,{...t,httpRequest:{...t?.httpRequest,url:t?.httpRequest?.url?.replace("//localhost","//host.containers.internal")}})}};function R(o){let e=new Uint8Array(3);crypto.getRandomValues(e);let t=Buffer.from(e).toString("hex");return`${o}-${new Date().getTime()}-${t}`}i(R,"createUniqueName");function g(o){return o instanceof Error&&"code"in o&&Number.isInteger(o.code)}i(g,"isRpcError");function c(o){return g(o)?{...o,type:"rpc"}:{type:"unknown",error:o}}i(c,"toTasksError");
@@ -0,0 +1,51 @@
1
+ import { CloudTasksClient } from "@google-cloud/tasks";
2
+ import type { google } from "@google-cloud/tasks/build/protos";
3
+ import { Status } from "google-gax";
4
+ import type { Result } from "ts-results-es";
5
+ import { Err, Ok } from "ts-results-es";
6
+ import type { Logger } from "./client";
7
+ export type GcpLocation = "europe-west6" | (string & NonNullable<unknown>);
8
+ type RpcError = {
9
+ type: "rpc";
10
+ code: Status;
11
+ } & Error;
12
+ type UnknownError = {
13
+ type: "unknown";
14
+ error: unknown;
15
+ };
16
+ export type TasksError = RpcError | UnknownError;
17
+ export type TaskConfig = Omit<google.cloud.tasks.v2.ITask, "name">;
18
+ export interface TasksClient {
19
+ upsertQueue(options?: Omit<google.cloud.tasks.v2.IQueue, "name">): Promise<Result<void, TasksError>>;
20
+ getTask(taskPath: string): Promise<Result<google.cloud.tasks.v2.ITask | null, TasksError>>;
21
+ listTasks(): Promise<Result<google.cloud.tasks.v2.ITask[], TasksError>>;
22
+ createTask(taskName: string, task: TaskConfig): Promise<Result<string, TasksError>>;
23
+ }
24
+ declare class CommonTasksClient implements TasksClient {
25
+ protected readonly client: CloudTasksClient;
26
+ protected readonly location: GcpLocation;
27
+ protected readonly queueName: string;
28
+ protected readonly logger: Logger;
29
+ protected serviceAccountEmailPromise: Promise<string | null>;
30
+ protected projectIdPromise: Promise<string>;
31
+ constructor(client: CloudTasksClient, location: GcpLocation, queueName: string, logger: Logger);
32
+ upsertQueue(options?: Omit<google.cloud.tasks.v2.IQueue, "name">): Promise<Err<TasksError> | import("ts-results-es").OkImpl<void>>;
33
+ listTasks(): Promise<Err<TasksError> | Ok<google.cloud.tasks.v2.ITask[]>>;
34
+ createTask(taskName: string, task: TaskConfig): Promise<Err<TasksError> | Ok<string>>;
35
+ getTask(name: string): Promise<Err<TasksError> | Ok<google.cloud.tasks.v2.ITask> | Ok<null>>;
36
+ }
37
+ export declare class RegularTasksClient extends CommonTasksClient {
38
+ constructor(location: GcpLocation, queueName: string, logger: Logger);
39
+ }
40
+ export type EmulatorConfig = {
41
+ /** default: "localhost" */
42
+ host?: string;
43
+ port?: number;
44
+ };
45
+ export declare class EmulatorTasksClient extends CommonTasksClient {
46
+ constructor(location: GcpLocation, queueName: string, logger: Logger, config: EmulatorConfig);
47
+ upsertQueue(options?: Omit<google.cloud.tasks.v2.IQueue, "name">): Promise<Err<TasksError> | import("ts-results-es").OkImpl<void>>;
48
+ createTask(taskName: string, task: TaskConfig): Promise<Err<TasksError> | Ok<string>>;
49
+ }
50
+ export {};
51
+ //# sourceMappingURL=tasksClients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasksClients.d.ts","sourceRoot":"","sources":["../src/tasksClients.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ var y=Object.defineProperty;var a=(o,e)=>y(o,"name",{value:e,configurable:!0});import{CloudTasksClient as k}from"@google-cloud/tasks";import{credentials as P}from"@grpc/grpc-js";import{GoogleAuth as T}from"google-auth-library";import{Status as g}from"google-gax";import{Err as c,Ok as i}from"ts-results-es";var p=class{constructor(e,t,r,n){this.client=e;this.location=t;this.queueName=r;this.logger=n;this.projectIdPromise=this.client.getProjectId(),this.serviceAccountEmailPromise=new T().getCredentials().then(s=>s.client_email??null)}static{a(this,"CommonTasksClient")}serviceAccountEmailPromise;projectIdPromise;async upsertQueue(e){try{let t=await this.projectIdPromise,r=this.client.queuePath(t,this.location,this.queueName),n=this.client.locationPath(t,this.location);this.logger.info({queuePath:r,parentPath:n},"upserting tasks queue");let s="create";try{await this.client.getQueue({name:r}),s="update"}catch(u){if(h(u)&&u.code===g.NOT_FOUND)s="create";else throw u}return s==="update"?(this.logger.info({queuePath:r},"updating existing queue"),await this.client.updateQueue({queue:{name:r,...e}})):(this.logger.info({queuePath:r},"creating new queue"),await this.client.createQueue({parent:n,queue:{name:r,...e}})),i.EMPTY}catch(t){return c(l(t))}}async listTasks(){try{let e=await this.projectIdPromise,t=this.client.queuePath(e,this.location,this.queueName),[r]=await this.client.listTasks({parent:t});return i(r)}catch(e){return c(l(e))}}async createTask(e,t){try{let r=await this.projectIdPromise,n=this.client.queuePath(r,this.location,this.queueName),s=this.client.taskPath(r,this.location,this.queueName,f(e)),u=await this.serviceAccountEmailPromise;return this.logger.info({queuePath:n,taskPath:s,url:t?.httpRequest?.url,payload:t?.httpRequest?.body,serviceAccountEmail:u},"scheduling task"),await this.client.createTask({parent:n,task:{...t,name:s,httpRequest:{...t?.httpRequest,oidcToken:{serviceAccountEmail:u}}}}),i(s)}catch(r){return c(l(r))}}async getTask(e){try{let[t]=await this.client.getTask({name:e});return i(t)}catch(t){return h(t)&&t.code===g.NOT_FOUND?i(null):c(l(t))}}},m=class extends p{static{a(this,"RegularTasksClient")}constructor(e,t,r){super(new k({}),e,t,r)}},d=class extends p{static{a(this,"EmulatorTasksClient")}constructor(e,t,r,n){super(new k({sslCreds:P.createInsecure(),servicePath:n.host??"localhost",port:n.port}),e,t,r)}async upsertQueue(e){try{let t=await this.projectIdPromise,r=this.client.queuePath(t,this.location,this.queueName),n=this.client.locationPath(t,this.location);this.logger.info({queuePath:r,parentPath:n},"upserting simulator tasks queue");try{return await this.client.createQueue({parent:n,queue:{name:r,...e}}),i.EMPTY}catch(s){return h(s)&&s.code!==g.ALREADY_EXISTS?c(l(s)):(this.logger.warn({},"dev warning: the queue was not updated due to the emulator not supporting update"),this.logger.warn({},"if you need to update queue options, restart the emulator"),i.EMPTY)}}catch(t){return c(l(t))}}async createTask(e,t){return super.createTask(e,{...t,httpRequest:{...t?.httpRequest,url:t?.httpRequest?.url?.replace("//localhost","//host.containers.internal")}})}};function f(o){let e=new Uint8Array(3);crypto.getRandomValues(e);let t=Buffer.from(e).toString("hex");return`${o}-${new Date().getTime()}-${t}`}a(f,"createUniqueName");function h(o){return o instanceof Error&&"code"in o&&Number.isInteger(o.code)}a(h,"isRpcError");function l(o){return h(o)?{...o,type:"rpc"}:{type:"unknown",error:o}}a(l,"toTasksError");export{d as EmulatorTasksClient,m as RegularTasksClient};
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@panter/cloud-tasks",
3
+ "repository": {
4
+ "type": "git",
5
+ "url": "https://git.panter.ch/open-source/cloud-tasks.git"
6
+ },
7
+ "version": "0.0.0-chore-logger-readme-4678c841",
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "./client": {
21
+ "import": {
22
+ "types": "./dist/client.d.ts",
23
+ "default": "./dist/client.mjs"
24
+ },
25
+ "require": {
26
+ "types": "./dist/client.d.ts",
27
+ "default": "./dist/client.cjs"
28
+ }
29
+ },
30
+ "./server": {
31
+ "import": {
32
+ "types": "./dist/server.d.ts",
33
+ "default": "./dist/server.mjs"
34
+ },
35
+ "require": {
36
+ "types": "./dist/server.d.ts",
37
+ "default": "./dist/server.cjs"
38
+ }
39
+ }
40
+ },
41
+ "files": [
42
+ "dist"
43
+ ],
44
+ "scripts": {
45
+ "build": "rm -rf dist/ && tsc -d --emitDeclarationOnly --declarationDir ./dist/ --noEmit false && node build.mjs",
46
+ "lint": "yarn biome check .",
47
+ "test": "echo 'todo: write tests'"
48
+ },
49
+ "dependencies": {
50
+ "@google-cloud/tasks": "^5.5.2",
51
+ "@trpc/client": "^10.45.2",
52
+ "@trpc/server": "^10.45.2",
53
+ "express": "^4.21.2",
54
+ "ts-results-es": "^4.2.0"
55
+ },
56
+ "devDependencies": {
57
+ "@biomejs/biome": "1.9.4",
58
+ "@types/express": "^4.17.21",
59
+ "esbuild": "^0.24.2",
60
+ "prettier": "^3.4.2",
61
+ "typescript": "5.7.3"
62
+ },
63
+ "packageManager": "yarn@4.6.0",
64
+ "stableVersion": "0.0.0"
65
+ }