rudderstash 0.1.1 → 0.1.2
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 +5 -2
- package/dist/rudderstash.js +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ mkdir project && cd project
|
|
|
19
19
|
|
|
20
20
|
A read-write Rudderstack API token is required for synchronization. This can either be [Personal Access Token](https://app.rudderstack.com/profile) or a [Service Access Token](https://app.rudderstack.com/organization?tab=service_access_tokens). Set the `RUDDERSTACK_API_TOKEN` in the .env file in the project root or supply it via environment variables. See .env.example, and remember to **never commit your .env file**.
|
|
21
21
|
|
|
22
|
-
The `RUDDERSTACK_API_USER` (matches your account email) and `RUDDERSTACK_API_ENDPOINT` should also be supplied.
|
|
22
|
+
The `RUDDERSTACK_API_USER` (matches your account email) and `RUDDERSTACK_API_ENDPOINT` should also be supplied (either `https://api.rudderstack.com` for US-based data planes or `https://api.eu.rudderstack.com` for EU ones).
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
rudderstash status
|
|
@@ -54,7 +54,10 @@ Testing is simple. Add a `MyTransformation.tests.json` file corresponding to the
|
|
|
54
54
|
"expected": {
|
|
55
55
|
"ip": "127.0.X.X",
|
|
56
56
|
"browser": "Chrome",
|
|
57
|
-
}
|
|
57
|
+
},
|
|
58
|
+
"metadata": {
|
|
59
|
+
"destinationId": "....",
|
|
60
|
+
},
|
|
58
61
|
}
|
|
59
62
|
]
|
|
60
63
|
```
|
package/dist/rudderstash.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";import{writeFile as
|
|
3
|
-
`),console.info("Upstream:"),!Object.keys(
|
|
4
|
-
`);else for(const
|
|
2
|
+
"use strict";import{writeFile as p,readdir as I,readFile as g}from"fs/promises";import"colors";import D from"dotenv";import k from"yargs";import{hideBin as P}from"yargs/helpers";import{diffJson as J}from"diff";import{existsSync as v}from"fs";import{writeFile as $,readdir as O,readFile as l}from"fs/promises";import{createHash as T}from"crypto";var S="0.1.2",R="[24ac473@trunk; built: 2025-12-25T11:10:26Z]",y=class{headers={};endpoint;constructor(c){this.endpoint=c.RUDDERSTACK_API_ENDPOINT,this.headers={"User-Agent":`rudderstash/${S}`,"Content-Type":"application/json",Authorization:"Basic "+Buffer.from(`${c.RUDDERSTACK_API_USER}:${c.RUDDERSTACK_API_TOKEN}`).toString("base64")}}async get(c){return(await fetch(this.endpoint+c,{headers:this.headers})).json()}async post(c,a){return(await fetch(this.endpoint+c,{method:"POST",headers:this.headers,body:JSON.stringify(a)})).json()}},b=class _{id;versionId;createdAt;updatedAt;name;description;code="";path;constructor(a={}){this.id=a.id,this.versionId=a.versionId,this.createdAt=a.createdAt,this.updatedAt=new Date(a.updatedAt),this.name=a.name}static async get(a){const i=await O(".");for(const s of i.filter(o=>o.endsWith(".transformation.js"))){const o=await l(s,"utf-8");if(!v(`${s}on`))continue;const t=JSON.parse(await l(`${s}on`,"utf-8"));if(t.id===a){const e=new _(t);return e.code=o,e}}return null}hash(){return T("sha1").update(JSON.stringify({id:this.id,code:this.code})).digest("hex")}},u=class N{transformations=[];api;constructor(a){this.api=new y(a)}static async read(a){const i=new N(a),s=await O(".");for(const o of s.filter(t=>t.endsWith(".transformation.js"))){if(!v(`${o}on`)){const n=new b;n.name=o.split(".transformation.js").at(0),n.code=await l(o,"utf-8"),n.path=o,i.transformations.push(n);continue}const t=JSON.parse(await l(`${o}on`,"utf-8")),e=await b.get(t.id);e&&(e.path=o,i.transformations.push(e))}return await i.fetch(),i}async fetch(){v(".ruddercache")||await $(".ruddercache","{}");const a=JSON.parse(await l(".ruddercache","utf8"));a.transformations=(await this.api.get("/transformations")).transformations,a.transformations_fetched_at=Date.now(),await $(".ruddercache",JSON.stringify(a))}async list(){v(".ruddercache")||await $(".ruddercache","{}");let a=JSON.parse(await l(".ruddercache","utf8"));a.transformations===void 0&&(this.fetch(),a=JSON.parse(await l(".ruddercache","utf8")));const i=a.transformations,s={},o={};for(const t of i){const e=t.id;s[e]=new b(t),s[e].code=t.code}for(const t of this.transformations){const e=t.id??crypto.randomUUID();t.id=e,o[e]||(o[e]=[]),o[e].push(t)}return{transformations_fetched_at:a.transformations_fetched_at,transformations:[s,o]}}},d={};D.config({quiet:!0,processEnv:d,override:!1}),Object.entries(d).forEach(([c,a])=>{c in process.env&&(d[c]=process.env[c])});var E=await k(P(process.argv)).parse(),[U,...M]=E._;switch(U){case"version":{console.info(`rudderstash ${S} ${R}`);break}case"status":{const a=await(await u.read(d)).list(),[i,s]=a.transformations;if(console.info(`Last fetched ${new Date(a.transformations_fetched_at)}
|
|
3
|
+
`),console.info("Upstream:"),!Object.keys(i).length)console.info(` (none)
|
|
4
|
+
`);else for(const o of Object.values(i)){let t=" ";const e=[];if(s[o.id]===void 0)t="+";else{const n=(s[o.id]??[]).reduce((f,h)=>f||h.hash()!==o.hash(),!1),r=(s[o.id]??[]).reduce((f,h)=>f||h.name!==o.name||h.description!==o.description,!1);n&&(t="~"),r&&(t="~",e.push("metadata changed")),!n&&!r&&e.push("no changes")}console.info(` ${t} ${o.hash().substring(0,7)} ${o.name}`+(e.length?` (${e.join(", ")})`:""))}if(console.info(`
|
|
5
5
|
Local:`),!Object.keys(s).length)console.info(` (none)
|
|
6
|
-
`);else for(const
|
|
7
|
-
`)+". Resolve by leaving only one.".red);continue}const
|
|
8
|
-
`).map(
|
|
6
|
+
`);else for(const o of Object.values(s))for(const t of o){let e=" ",n=[];o.filter(f=>f.id===t.id).length>1&&(e="!",n.push("duplicate")),i[t.id]===void 0&&(e="+"),console.info(` ${e} ${t.hash().substring(0,7)} ${t.name} (${t.path})`+(n.length?` (${n.join(", ")})`:""))}break}case"pull":{const a=await(await u.read(d)).list(),[i,s]=a.transformations;if(Object.keys(i).length<1){console.info("No transformations upstream, nothing to pull.");break}for(const o of Object.values(i))if(s[o.id])for(const t of Object.values(s[o.id])){const e=t.path;console.info(`< Pulling new transformation ${o.name} to ${e}...`),await p(e,o.code),console.info(`< Saving metadata to ${e}on.`),delete o.code,await p(e+"on",JSON.stringify(o,null,2))}else{const t=o.name.split(" ").map(e=>e[0].toUpperCase()+e.substring(1)).join("")+".transformation.js";console.info(`< Pulling new transformation ${o.name} to ${t}...`),await p(t,o.code),console.info(`< Saving metadata to ${t}on.`),delete o.code,await p(t+"on",JSON.stringify(o,null,2))}break}case"push":{const a=await(await u.read(d)).list(),[i,s]=a.transformations;if(Object.values(s).length<1){console.info("No local transformations, nothing to push.");break}const o=new y(d);for(const t of Object.values(s)){if(Object.values(t).length>1){console.warn("Conflict! The following local transformations have the same ID: "+Object.values(t).map(f=>f.path).join(`
|
|
7
|
+
`)+". Resolve by leaving only one.".red);continue}const e=await g(t[0].path,"utf-8");let n={};if(t[0].versionId===void 0?(n.id="",n.name=t[0].path.split(".transformation.js").at(0),n.description=t[0].path):n=JSON.parse(await g(`${t[0].path}on`,"utf-8")),i[t[0].id]&&t[0].hash()===i[t[0].id].hash()){console.info(`> Skipping ${n.name} transformation. No changes.`);continue}console.info(`> Pushing ${e.length} bytes of code to ${n.name} transformation...`);const r=await o.post(`/transformations/${n.id}?publish=true`,{code:e,name:n.name,language:"javascript",description:n.description});if(r.error!==void 0){console.error(r.error);continue}delete r.code,await p(`${t[0].path}on`,JSON.stringify({...n,...r},null,2)),console.info(`> Published with version ${r.versionId}.`),console.info("< Metadata updated.")}break}case"diff":{const a=await(await u.read(d)).list()}case"revert":break;case"test":{const a=await(await u.read(d)).list(),[i,s]=a.transformations,o=(await I(".")).filter(t=>t.endsWith(".tests.json"));o.length<1&&(console.error("No tests to run [*.tests.json].".red),process.exit(-1));for(const t of o)Object.values(s).flat().find(n=>n.path===t.replace(".tests.json",".transformation.js"))===void 0&&(console.error(`${t} has no matching ${t.replace(".tests.json",".transformation.js")} file.`.red),process.exit(-1));process.removeAllListeners("warning");for(const t of o){const e=Object.values(s).flat().find(r=>r.path===t.replace(".tests.json",".transformation.js"));console.info(`${e.name}:`);const n=JSON.parse(await g(t,"utf8"));for(const r of n){let f=" ERR";const A=(await import(`file://${process.cwd()}/${e.path}`)).transformEvent(r.input,()=>Object.assign({destinationId:void 0,destinationName:void 0,destinationType:void 0,sourceId:void 0,sourceName:void 0,sourceType:void 0},r.metadata??{})),w=J(r.expected??{_is_null:!0},A??{_is_null:!0});switch(f="FAIL",w.length===1&&!w[0].added&&!w[0].removed&&(f="PASS"),f){case"FAIL":console.warn(` ${f} - ${t.split(".json").at(0)}: ${r.name} `.red);for(const m of w){if(!m.added&&!m.removed){console.warn();continue}m.added&&console.warn(m.value.trim().split(`
|
|
8
|
+
`).map(j=>` + ${j}`).join(`
|
|
9
9
|
`)),m.removed&&console.warn(m.value.trim().split(`
|
|
10
|
-
`).map(
|
|
11
|
-
`))}break;case"PASS":console.info(` ${f} - ${t.split(".json").at(0)}: ${
|
|
10
|
+
`).map(j=>` - ${j}`).join(`
|
|
11
|
+
`))}break;case"PASS":console.info(` ${f} - ${t.split(".json").at(0)}: ${r.name} `.green);break;default:console.info(` ${f} - ${t.split(".json").at(0)}: ${r.name} `.bgRed);break}}}break}default:console.error("Unknown command. Did you mean any of these: status, pull, push, test?".red)}
|