@prisma/extension-optimize 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.
@@ -0,0 +1,35 @@
1
+ import * as _prisma_client_extension from '@prisma/client/extension';
2
+ import * as _prisma_client_runtime_library from '@prisma/client/runtime/library';
3
+
4
+ declare const PROD_INGESTION_URL = "https://optimize-ingestion.datacdn.workers.dev/";
5
+ declare const PROD_DASHBOARD_URL = "https://optimize-3k7.pages.dev/";
6
+ type OptimizeOptions = {
7
+ /**
8
+ * Whether to enable Prisma Optimize. Defaults to `true`.
9
+ */
10
+ enable?: boolean;
11
+ /**
12
+ * The URL of the ingestion service of Prisma Optimize.
13
+ */
14
+ ingestionUrl?: string;
15
+ /**
16
+ * The URL of the dashboard of Prisma Optimize
17
+ */
18
+ dashboardUrl?: string;
19
+ /**
20
+ * Whether to use tracing or not. Requires the `tracing` preview feature to be enabled,
21
+ * hence disabled by default to maximize compatibility. Basic functionality is available
22
+ * without tracing but capturing the SQL statements and detecting cold starts is only
23
+ * available with tracing.
24
+ */
25
+ useTracing?: boolean;
26
+ /**
27
+ * The minimum interval in milliseconds between sending batched requests to the ingestion service.
28
+ * This is only currently used when tracing is enabled. When tracing is disabled, the requests
29
+ * are not batched, and are sent immediately on the next event loop tick.
30
+ */
31
+ minSendInterval?: number;
32
+ };
33
+ declare function withOptimize({ enable, ingestionUrl, dashboardUrl, useTracing, minSendInterval, }?: OptimizeOptions): (client: any) => _prisma_client_extension.PrismaClientExtends<_prisma_client_runtime_library.InternalArgs<{}, {}, {}, {}> & _prisma_client_runtime_library.DefaultArgs>;
34
+
35
+ export { type OptimizeOptions, PROD_DASHBOARD_URL, PROD_INGESTION_URL, withOptimize };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";var de=Object.create;var f=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var ce=Object.getOwnPropertyNames;var le=Object.getPrototypeOf,me=Object.prototype.hasOwnProperty;var ue=(t,e)=>{for(var n in e)f(t,n,{get:e[n],enumerable:!0})},L=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ce(e))!me.call(t,r)&&r!==n&&f(t,r,{get:()=>e[r],enumerable:!(o=pe(e,r))||o.enumerable});return t};var a=(t,e,n)=>(n=t!=null?de(le(t)):{},L(e||!t||!t.__esModule?f(n,"default",{value:t,enumerable:!0}):n,t)),fe=t=>L(f({},"__esModule",{value:!0}),t);var qe={};ue(qe,{PROD_DASHBOARD_URL:()=>ae,PROD_INGESTION_URL:()=>ie,withOptimize:()=>xe});module.exports=fe(qe);var oe=require("@opentelemetry/api"),re=require("@prisma/client/extension"),se=a(require("@prisma/debug")),b=require("kleur");var q;async function h(t,e,n){let o=new URL("/ingest",t),r=new Headers({"Content-Type":"application/json",Authorization:`Bearer ${e}`});q&&r.set("prisma-optimize-jwt",q);let s=await fetch(o,{method:"POST",headers:r,body:JSON.stringify(n)});if(!s.ok){console.error(`[optimize] HTTP ${s.status} ${s.statusText}: ${await s.text()}`);return}let i=s.headers.get("prisma-optimize-jwt");i&&(q=i)}var M=a(require("fs")),U=a(require("path")),F=a(require("@prisma/debug")),_=a(require("xdg-app-paths")),he=(0,F.default)("prisma:extension:optimize"),ge=new _.default("prisma-platform-cli").config(),Se=U.default.join(ge,"auth.json");function ye(t){if(typeof t!="object"||t===null)throw new Error("Invalid credentials");if(typeof t.token!="string")throw new Error("Invalid credentials");return t}function D(){try{let t=M.default.readFileSync(Se,"utf-8");return ye(JSON.parse(t)).token}catch(t){return he(t),null}}var c=a(require("fs")),$=a(require("path")),N=require("stream"),j=require("stream/promises"),g=require("kleur"),J=require("node-notifier"),B=a(require("xdg-app-paths")),we="https://avatars.githubusercontent.com/u/17219288?s=96";async function Re(t){let e=new B.default("prisma-optimize").config();c.default.mkdirSync(e,{recursive:!0});let n=$.default.resolve(e,"avatar.png");if(!c.default.existsSync(n)){let p=await fetch(we);if(p.ok&&p.body!=null){let I=c.default.createWriteStream(n,{flags:"wx"});await(0,j.finished)(N.Readable.fromWeb(p.body).pipe(I))}}let o="See your Optimize dashboard at:",r=o.length,s=`${(0,g.underline)((0,g.bold)(t))}`,i=t.length,d=Math.max(r,i)+2;console.log("\u250C"+"\u2500".repeat(d)+"\u2510"),console.log("\u2502 "+o+" ".repeat(d-r-2)+" \u2502"),console.log("\u2502 "+s+" ".repeat(d-i-2)+" \u2502"),console.log("\u2514"+"\u2500".repeat(d)+"\u2518"),(0,J.notify)({timeout:10,open:t,subtitle:"Your dashboard is ready! \u{1F680} ",message:"Click to open",title:"Prisma Optimize",icon:c.default.existsSync(n)?n:void 0,contentImage:c.default.existsSync(n)?n:void 0})}var H={dashboardReady:Re};var V=require("@opentelemetry/api"),G=require("@opentelemetry/context-async-hooks"),W=require("@opentelemetry/instrumentation"),X=require("@opentelemetry/resources"),Y=require("@opentelemetry/sdk-trace-base"),R=require("@opentelemetry/semantic-conventions"),Z=require("@prisma/instrumentation");var Q=a(require("@prisma/debug"));function S(t,...e){setTimeout(()=>{t(...e)},0)}function v(t){return t[0]*1e3+t[1]/1e6}var y=(0,Q.default)("prisma:extension:optimize"),P="0000000000000000",T=class{spanId;timestamp;model;operation;args;duration;connect;sql;error;completionFlags={clientSpanClosed:!1,engineSpanClosed:!1};constructor(e){this.spanId=e.spanId,this.timestamp=e.timestamp,this.model=e.model,this.operation=e.operation,this.args=e.args}#e(){return this.completionFlags.clientSpanClosed&&this.completionFlags.engineSpanClosed}completedRequest(){if(this.#e()&&this.error!==void 0){if(this.duration===void 0)throw new Error("Invariant violation: duration cannot still be undefined after the client span is closed because it is retrieved from the client span. This is a bug.");return{ts:this.timestamp,model:this.model??null,operation:this.operation,args:this.args,latency:this.duration,connect:this.connect??!1,sql:this.sql??null,error:this.error}}}},w=class{#e=new Map;#r=Promise.resolve();#t=new Map;#n=new Map;#i;#a;#d;#o=[];#s=!1;#p=0;constructor(e,n,o){this.#i=e,this.#a=n,this.#d=o}createRequest(e){let n=new T(e);this.#e.set(e.spanId,n)}setRequestError(e,n){let o=this.#e.get(e);if(!o)throw new Error(`Unknown request ${e}`);o.error=n}#u(e){for(let n=e;n!==P;n=this.#t.get(n)){if(n===void 0)return{type:"UndeliveredSpanInTree"};let o=this.#e.get(n);if(o)return{type:"Ok",request:o}}return{type:"NotInRequestTree"}}onStart(e,n){let o=e.spanContext().spanId;if(!e.parentSpanId){this.#t.set(o,P);return}if(this.#t.set(o,e.parentSpanId),e.parentSpanId===P)return;let r=this.#n.get(e.parentSpanId);r?r.add(o):this.#n.set(e.parentSpanId,new Set([o]))}onEnd(e){this.#c(e)}async forceFlush(){await this.#r,await this.#m()}async shutdown(){await this.forceFlush()}#c(e){let n=e.spanContext().spanId,o,r=this.#u(n);switch(r.type){case"Ok":o=r.request;break;case"UndeliveredSpanInTree":this.#f(e);break;case"NotInRequestTree":this.#l(n);break}if(!o)return;switch(e.name){case"prisma:client:connect":{o.connect=v(e.duration);break}case"prisma:engine:db_query":{let i=e.attributes["db.statement"];typeof i=="string"?o.sql=i:y("db.statement in span %s must be a string, got %o",n,i),o.completionFlags.engineSpanClosed=!0;break}case"prisma:client:operation":{let i=v(e.duration);y("latency otel: %d",i),o.duration=i,o.completionFlags.clientSpanClosed=!0;break}}let s=o.completedRequest();s&&(this.#e.delete(o.spanId),this.#h(s))}#f(e){this.#r=Promise.all([this.#r,new Promise(n=>{S(()=>{this.#c(e),n()})})]).then(()=>{})}#l(e){this.#t.delete(e);let n=this.#n.get(e);if(this.#n.delete(e),n)for(let o of n)this.#l(o)}#h(e){this.#o.push(e),this.#g()}#g(){if(this.#s)return;this.#s=!0;let e=Date.now()-this.#p;y("time since last send: %d",e),setTimeout(()=>{this.#s=!1,this.#m()},Math.max(0,this.#d-e))}async#m(){if(this.#o.length===0)return;let e=this.#o;this.#o=[],y("sending batch of %d requests",e.length),this.#p=Date.now(),await h(this.#i,this.#a,e)}};function K(t,e,n){let o=new G.AsyncHooksContextManager().enable();V.context.setGlobalContextManager(o);let r=new Y.BasicTracerProvider({resource:new X.Resource({[R.SEMRESATTRS_SERVICE_NAME]:"extension-optimize",[R.SEMRESATTRS_SERVICE_VERSION]:"0.0.0"})}),s=new w(t,e,n);return r.addSpanProcessor(s),(0,W.registerInstrumentations)({tracerProvider:r,instrumentations:[new Z.PrismaInstrumentation]}),r.register(),s}function ee(t){if(t instanceof Error)return t.stack??t.message;switch(typeof t){case"undefined":return"undefined";case"object":{let e;return t!==null&&typeof t.toString=="function"&&(e=t.toString()),typeof e=="string"&&e!=="[object Object]"?e:JSON.stringify(t)}default:return String(t)}}var te=require("@prisma/client/extension"),ne=te.Prisma.defineExtension(t=>t.$extends({}));var be=(0,se.default)("prisma:extension:optimize"),ie="https://optimize-ingestion.datacdn.workers.dev/",ae="https://optimize-3k7.pages.dev/",Ie=`Please login to Prisma Data Platform using the CLI to use Prisma Optimize:
2
+
3
+ ${(0,b.dim)("$")} ${(0,b.bold)("prisma platform auth login --early-access")}
4
+ `;function xe({enable:t=!0,ingestionUrl:e=ie,dashboardUrl:n=ae,useTracing:o=!1,minSendInterval:r=10}={}){if(!t)return ne;let s=new URL(e),i=D();if(!i)throw new Error(Ie);return H.dashboardReady(n).then().catch(d=>{console.error("Failed to show toast",d)}),re.Prisma.defineExtension(d=>{let p=o?K(s,i,r):void 0;return d.$extends({query:{async $allOperations({query:I,model:k,operation:E,args:x}){let C=oe.trace.getActiveSpan();if(o&&!C)throw new Error("prisma:client:operation span is expected to be entered in the client extension when tracing is enabled");let m=C?.spanContext().spanId,u=null,A=performance.now(),O=Date.now();m&&p?.createRequest({spanId:m,timestamp:O,model:k,operation:E,args:x});try{return await I(x)}catch(l){throw u=ee(l),await p?.forceFlush(),l}finally{let l=performance.now();if(be("latency raw: %d",l-A),m&&p?.setRequestError(m,u),!o){let z=async()=>{await h(s,i,[{model:k??null,operation:E,args:x,error:u,latency:l-A,ts:O,connect:!1,sql:null}])};u!==null?await z():S(z)}}}}})})}0&&(module.exports={PROD_DASHBOARD_URL,PROD_INGESTION_URL,withOptimize});
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@prisma/extension-optimize",
3
+ "version": "0.5.0",
4
+ "description": "",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "scripts": {
8
+ "typecheck": "tsc --noEmit",
9
+ "build": "tsup src/index.ts --minify --dts --format cjs --out-dir dist",
10
+ "lint": "eslint --fix .",
11
+ "test": "vitest --run"
12
+ },
13
+ "keywords": [],
14
+ "dependencies": {
15
+ "@opentelemetry/api": "1.8.0",
16
+ "@opentelemetry/context-async-hooks": "1.22.0",
17
+ "@opentelemetry/exporter-trace-otlp-http": "0.49.1",
18
+ "@opentelemetry/instrumentation": "0.49.1",
19
+ "@opentelemetry/resources": "1.22.0",
20
+ "@opentelemetry/sdk-trace-base": "1.22.0",
21
+ "@opentelemetry/semantic-conventions": "1.22.0",
22
+ "@prisma/debug": "5.12.1",
23
+ "@prisma/instrumentation": "5.11.0",
24
+ "node-notifier": "10.0.1",
25
+ "kleur": "4.1.5",
26
+ "xdg-app-paths": "8.3.0"
27
+ },
28
+ "devDependencies": {
29
+ "common": "workspace:*",
30
+ "tsup": "8.0.2",
31
+ "@types/node-notifier": "8.0.5",
32
+ "vitest": "1.4.0"
33
+ },
34
+ "peerDependencies": {
35
+ "@prisma/client": "5.x"
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ]
40
+ }