pepr 0.13.4 → 0.14.1

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 (106) hide show
  1. package/README.md +25 -5
  2. package/commitlint.config.js +1 -0
  3. package/dist/cli.js +375 -204
  4. package/dist/controller.js +1 -1
  5. package/dist/lib/assets/deploy.d.ts.map +1 -1
  6. package/dist/lib/assets/destroy.d.ts +2 -0
  7. package/dist/lib/assets/destroy.d.ts.map +1 -0
  8. package/dist/lib/assets/index.d.ts +6 -5
  9. package/dist/lib/assets/index.d.ts.map +1 -1
  10. package/dist/lib/assets/networking.d.ts +6 -5
  11. package/dist/lib/assets/networking.d.ts.map +1 -1
  12. package/dist/lib/assets/pods.d.ts +84 -4
  13. package/dist/lib/assets/pods.d.ts.map +1 -1
  14. package/dist/lib/assets/rbac.d.ts +6 -4
  15. package/dist/lib/assets/rbac.d.ts.map +1 -1
  16. package/dist/lib/assets/store.d.ts +7 -0
  17. package/dist/lib/assets/store.d.ts.map +1 -0
  18. package/dist/lib/assets/webhooks.d.ts +2 -2
  19. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  20. package/dist/lib/assets/yaml.d.ts.map +1 -1
  21. package/dist/lib/capability.d.ts +21 -4
  22. package/dist/lib/capability.d.ts.map +1 -1
  23. package/dist/lib/controller/index.d.ts +10 -0
  24. package/dist/lib/controller/index.d.ts.map +1 -0
  25. package/dist/lib/controller/store.d.ts +7 -0
  26. package/dist/lib/controller/store.d.ts.map +1 -0
  27. package/dist/lib/filter.d.ts +2 -2
  28. package/dist/lib/filter.d.ts.map +1 -1
  29. package/dist/lib/{k8s/types.d.ts → k8s.d.ts} +14 -25
  30. package/dist/lib/k8s.d.ts.map +1 -0
  31. package/dist/lib/metrics.d.ts +12 -12
  32. package/dist/lib/metrics.d.ts.map +1 -1
  33. package/dist/lib/module.d.ts +25 -4
  34. package/dist/lib/module.d.ts.map +1 -1
  35. package/dist/lib/mutate-processor.d.ts +3 -3
  36. package/dist/lib/mutate-processor.d.ts.map +1 -1
  37. package/dist/lib/mutate-request.d.ts +11 -10
  38. package/dist/lib/mutate-request.d.ts.map +1 -1
  39. package/dist/lib/storage.d.ts +56 -0
  40. package/dist/lib/storage.d.ts.map +1 -0
  41. package/dist/lib/tls.d.ts.map +1 -0
  42. package/dist/lib/types.d.ts +28 -48
  43. package/dist/lib/types.d.ts.map +1 -1
  44. package/dist/lib/validate-processor.d.ts +2 -2
  45. package/dist/lib/validate-processor.d.ts.map +1 -1
  46. package/dist/lib/validate-request.d.ts +9 -8
  47. package/dist/lib/validate-request.d.ts.map +1 -1
  48. package/dist/lib/watch-processor.d.ts +3 -0
  49. package/dist/lib/watch-processor.d.ts.map +1 -0
  50. package/dist/lib.d.ts +3 -7
  51. package/dist/lib.d.ts.map +1 -1
  52. package/dist/lib.js +484 -807
  53. package/dist/lib.js.map +4 -4
  54. package/package.json +20 -22
  55. package/src/lib/assets/deploy.ts +69 -127
  56. package/src/lib/assets/destroy.ts +33 -0
  57. package/src/lib/assets/index.ts +8 -14
  58. package/src/lib/assets/networking.ts +28 -5
  59. package/src/lib/assets/pods.ts +130 -11
  60. package/src/lib/assets/rbac.ts +42 -4
  61. package/src/lib/assets/store.ts +49 -0
  62. package/src/lib/assets/webhooks.ts +2 -2
  63. package/src/lib/assets/yaml.ts +13 -3
  64. package/src/lib/capability.ts +69 -14
  65. package/src/lib/{controller.ts → controller/index.ts} +25 -23
  66. package/src/lib/controller/store.ts +197 -0
  67. package/src/lib/filter.ts +2 -2
  68. package/src/lib/{k8s/types.ts → k8s.ts} +15 -26
  69. package/src/lib/metrics.ts +22 -38
  70. package/src/lib/module.ts +47 -10
  71. package/src/lib/mutate-processor.ts +6 -6
  72. package/src/lib/mutate-request.ts +18 -26
  73. package/src/lib/storage.ts +128 -0
  74. package/src/lib/types.ts +30 -53
  75. package/src/lib/validate-processor.ts +5 -4
  76. package/src/lib/validate-request.ts +15 -19
  77. package/src/lib/watch-processor.ts +55 -0
  78. package/src/lib.ts +4 -8
  79. package/src/templates/capabilities/hello-pepr.ts +54 -5
  80. package/src/templates/package.json +1 -0
  81. package/dist/lib/controller.d.ts +0 -10
  82. package/dist/lib/controller.d.ts.map +0 -1
  83. package/dist/lib/fetch.d.ts +0 -23
  84. package/dist/lib/fetch.d.ts.map +0 -1
  85. package/dist/lib/k8s/index.d.ts +0 -7
  86. package/dist/lib/k8s/index.d.ts.map +0 -1
  87. package/dist/lib/k8s/kinds.d.ts +0 -12
  88. package/dist/lib/k8s/kinds.d.ts.map +0 -1
  89. package/dist/lib/k8s/tls.d.ts.map +0 -1
  90. package/dist/lib/k8s/types.d.ts.map +0 -1
  91. package/dist/lib/k8s/upstream.d.ts +0 -4
  92. package/dist/lib/k8s/upstream.d.ts.map +0 -1
  93. package/jest.config.json +0 -4
  94. package/journey/before.ts +0 -21
  95. package/journey/k8s.ts +0 -100
  96. package/journey/pepr-build.ts +0 -69
  97. package/journey/pepr-deploy.ts +0 -174
  98. package/journey/pepr-dev.ts +0 -155
  99. package/journey/pepr-format.ts +0 -13
  100. package/journey/pepr-init.ts +0 -12
  101. package/src/lib/fetch.ts +0 -76
  102. package/src/lib/k8s/index.ts +0 -14
  103. package/src/lib/k8s/kinds.ts +0 -531
  104. package/src/lib/k8s/upstream.ts +0 -53
  105. /package/dist/lib/{k8s/tls.d.ts → tls.d.ts} +0 -0
  106. /package/src/lib/{k8s/tls.ts → tls.ts} +0 -0
package/dist/cli.js CHANGED
@@ -112,10 +112,10 @@ var import_path = require("path");
112
112
  // src/lib/assets/index.ts
113
113
  var import_crypto3 = __toESM(require("crypto"));
114
114
 
115
- // src/lib/k8s/tls.ts
115
+ // src/lib/tls.ts
116
116
  var import_node_forge = __toESM(require("node-forge"));
117
117
  var caName = "Pepr Ephemeral CA";
118
- function genTLS(name) {
118
+ function genTLS(name2) {
119
119
  const caKeys = import_node_forge.default.pki.rsa.generateKeyPair(2048);
120
120
  const caCert = genCert(caKeys, caName, [{ name: "commonName", value: caName }]);
121
121
  caCert.setExtensions([
@@ -133,7 +133,7 @@ function genTLS(name) {
133
133
  }
134
134
  ]);
135
135
  const serverKeys = import_node_forge.default.pki.rsa.generateKeyPair(2048);
136
- const serverCert = genCert(serverKeys, name, caCert.subject.attributes);
136
+ const serverCert = genCert(serverKeys, name2, caCert.subject.attributes);
137
137
  caCert.sign(caKeys.privateKey, import_node_forge.default.md.sha256.create());
138
138
  serverCert.sign(caKeys.privateKey, import_node_forge.default.md.sha256.create());
139
139
  const pem = {
@@ -146,7 +146,7 @@ function genTLS(name) {
146
146
  const crt = Buffer.from(pem.crt).toString("base64");
147
147
  return { ca, key, crt, pem };
148
148
  }
149
- function genCert(key, name, issuer) {
149
+ function genCert(key, name2, issuer) {
150
150
  const crt = import_node_forge.default.pki.createCertificate();
151
151
  crt.publicKey = key.publicKey;
152
152
  crt.serialNumber = "01";
@@ -160,7 +160,7 @@ function genCert(key, name, issuer) {
160
160
  {
161
161
  type: 2,
162
162
  // DNS
163
- value: name
163
+ value: name2
164
164
  }
165
165
  ]
166
166
  }
@@ -170,9 +170,9 @@ function genCert(key, name, issuer) {
170
170
  }
171
171
 
172
172
  // src/lib/assets/deploy.ts
173
- var import_client_node = require("@kubernetes/client-node");
174
173
  var import_crypto = __toESM(require("crypto"));
175
174
  var import_fs = require("fs");
175
+ var import_kubernetes_fluent_client2 = require("kubernetes-fluent-client");
176
176
 
177
177
  // src/lib/logger.ts
178
178
  var import_pino = require("pino");
@@ -193,12 +193,12 @@ if (process.env.LOG_LEVEL) {
193
193
  var logger_default = Log;
194
194
 
195
195
  // src/lib/assets/networking.ts
196
- function apiTokenSecret(name, apiToken) {
196
+ function apiTokenSecret(name2, apiToken) {
197
197
  return {
198
198
  apiVersion: "v1",
199
199
  kind: "Secret",
200
200
  metadata: {
201
- name: `${name}-api-token`,
201
+ name: `${name2}-api-token`,
202
202
  namespace: "pepr-system"
203
203
  },
204
204
  type: "Opaque",
@@ -207,12 +207,12 @@ function apiTokenSecret(name, apiToken) {
207
207
  }
208
208
  };
209
209
  }
210
- function tlsSecret(name, tls) {
210
+ function tlsSecret(name2, tls) {
211
211
  return {
212
212
  apiVersion: "v1",
213
213
  kind: "Secret",
214
214
  metadata: {
215
- name: `${name}-tls`,
215
+ name: `${name2}-tls`,
216
216
  namespace: "pepr-system"
217
217
  },
218
218
  type: "kubernetes.io/tls",
@@ -222,17 +222,38 @@ function tlsSecret(name, tls) {
222
222
  }
223
223
  };
224
224
  }
225
- function service(name) {
225
+ function service(name2) {
226
+ return {
227
+ apiVersion: "v1",
228
+ kind: "Service",
229
+ metadata: {
230
+ name: name2,
231
+ namespace: "pepr-system"
232
+ },
233
+ spec: {
234
+ selector: {
235
+ app: name2
236
+ },
237
+ ports: [
238
+ {
239
+ port: 443,
240
+ targetPort: 3e3
241
+ }
242
+ ]
243
+ }
244
+ };
245
+ }
246
+ function watcherService(name2) {
226
247
  return {
227
248
  apiVersion: "v1",
228
249
  kind: "Service",
229
250
  metadata: {
230
- name,
251
+ name: `${name2}-watcher`,
231
252
  namespace: "pepr-system"
232
253
  },
233
254
  spec: {
234
255
  selector: {
235
- app: name
256
+ app: `${name2}-watcher`
236
257
  },
237
258
  ports: [
238
259
  {
@@ -251,21 +272,32 @@ var namespace = {
251
272
  kind: "Namespace",
252
273
  metadata: { name: "pepr-system" }
253
274
  };
254
- function deployment(assets, hash) {
255
- const { name, image } = assets;
256
- const app = name;
275
+ function watcher(assets, hash) {
276
+ const { name: name2, image, capabilities, config } = assets;
277
+ const app = `${name2}-watcher`;
278
+ const bindings = [];
279
+ for (const capability of capabilities) {
280
+ const watchers = capability.bindings.filter((binding) => binding.isWatch);
281
+ bindings.push(...watchers);
282
+ }
283
+ if (bindings.length < 1) {
284
+ return null;
285
+ }
257
286
  return {
258
287
  apiVersion: "apps/v1",
259
288
  kind: "Deployment",
260
289
  metadata: {
261
- name,
290
+ name: app,
262
291
  namespace: "pepr-system",
263
292
  labels: {
264
293
  app
265
294
  }
266
295
  },
267
296
  spec: {
268
- replicas: 2,
297
+ replicas: 1,
298
+ strategy: {
299
+ type: "Recreate"
300
+ },
269
301
  selector: {
270
302
  matchLabels: {
271
303
  app
@@ -278,11 +310,10 @@ function deployment(assets, hash) {
278
310
  }
279
311
  },
280
312
  spec: {
281
- priorityClassName: "system-node-critical",
282
- serviceAccountName: name,
313
+ serviceAccountName: name2,
283
314
  containers: [
284
315
  {
285
- name: "server",
316
+ name: "watcher",
286
317
  image,
287
318
  imagePullPolicy: "IfNotPresent",
288
319
  command: ["node", "/app/node_modules/pepr/dist/controller.js", hash],
@@ -305,10 +336,106 @@ function deployment(assets, hash) {
305
336
  containerPort: 3e3
306
337
  }
307
338
  ],
339
+ resources: {
340
+ requests: {
341
+ memory: "64Mi",
342
+ cpu: "100m"
343
+ },
344
+ limits: {
345
+ memory: "256Mi",
346
+ cpu: "500m"
347
+ }
348
+ },
349
+ volumeMounts: [
350
+ {
351
+ name: "tls-certs",
352
+ mountPath: "/etc/certs",
353
+ readOnly: true
354
+ },
355
+ {
356
+ name: "module",
357
+ mountPath: `/app/load`,
358
+ readOnly: true
359
+ }
360
+ ],
308
361
  env: [
362
+ { name: "PEPR_WATCH_MODE", value: "true" },
363
+ { name: "PEPR_PRETTY_LOG", value: "false" },
364
+ { name: "LOG_LEVEL", value: config.logLevel || "debug" }
365
+ ]
366
+ }
367
+ ],
368
+ volumes: [
369
+ {
370
+ name: "tls-certs",
371
+ secret: {
372
+ secretName: `${name2}-tls`
373
+ }
374
+ },
375
+ {
376
+ name: "module",
377
+ secret: {
378
+ secretName: `${name2}-module`
379
+ }
380
+ }
381
+ ]
382
+ }
383
+ }
384
+ }
385
+ };
386
+ }
387
+ function deployment(assets, hash) {
388
+ const { name: name2, image, config } = assets;
389
+ const app = name2;
390
+ return {
391
+ apiVersion: "apps/v1",
392
+ kind: "Deployment",
393
+ metadata: {
394
+ name: name2,
395
+ namespace: "pepr-system",
396
+ labels: {
397
+ app
398
+ }
399
+ },
400
+ spec: {
401
+ replicas: 2,
402
+ selector: {
403
+ matchLabels: {
404
+ app
405
+ }
406
+ },
407
+ template: {
408
+ metadata: {
409
+ labels: {
410
+ app
411
+ }
412
+ },
413
+ spec: {
414
+ priorityClassName: "system-node-critical",
415
+ serviceAccountName: name2,
416
+ containers: [
417
+ {
418
+ name: "server",
419
+ image,
420
+ imagePullPolicy: "IfNotPresent",
421
+ command: ["node", "/app/node_modules/pepr/dist/controller.js", hash],
422
+ readinessProbe: {
423
+ httpGet: {
424
+ path: "/healthz",
425
+ port: 3e3,
426
+ scheme: "HTTPS"
427
+ }
428
+ },
429
+ livenessProbe: {
430
+ httpGet: {
431
+ path: "/healthz",
432
+ port: 3e3,
433
+ scheme: "HTTPS"
434
+ }
435
+ },
436
+ ports: [
309
437
  {
310
- name: "PEPR_PRETTY_LOG",
311
- value: "false"
438
+ containerPort: 3e3
312
439
  }
313
440
  ],
314
441
  resources: {
@@ -321,6 +448,10 @@ function deployment(assets, hash) {
321
448
  cpu: "500m"
322
449
  }
323
450
  },
451
+ env: [
452
+ { name: "PEPR_PRETTY_LOG", value: "false" },
453
+ { name: "LOG_LEVEL", value: config.logLevel || "debug" }
454
+ ],
324
455
  volumeMounts: [
325
456
  {
326
457
  name: "tls-certs",
@@ -344,19 +475,19 @@ function deployment(assets, hash) {
344
475
  {
345
476
  name: "tls-certs",
346
477
  secret: {
347
- secretName: `${name}-tls`
478
+ secretName: `${name2}-tls`
348
479
  }
349
480
  },
350
481
  {
351
482
  name: "api-token",
352
483
  secret: {
353
- secretName: `${name}-api-token`
484
+ secretName: `${name2}-api-token`
354
485
  }
355
486
  },
356
487
  {
357
488
  name: "module",
358
489
  secret: {
359
- secretName: `${name}-module`
490
+ secretName: `${name2}-module`
360
491
  }
361
492
  }
362
493
  ]
@@ -365,14 +496,14 @@ function deployment(assets, hash) {
365
496
  }
366
497
  };
367
498
  }
368
- function moduleSecret(name, data, hash) {
499
+ function moduleSecret(name2, data, hash) {
369
500
  const compressed = (0, import_zlib.gzipSync)(data);
370
501
  const path = `module-${hash}.js.gz`;
371
502
  return {
372
503
  apiVersion: "v1",
373
504
  kind: "Secret",
374
505
  metadata: {
375
- name: `${name}-module`,
506
+ name: `${name2}-module`,
376
507
  namespace: "pepr-system"
377
508
  },
378
509
  type: "Opaque",
@@ -383,11 +514,11 @@ function moduleSecret(name, data, hash) {
383
514
  }
384
515
 
385
516
  // src/lib/assets/rbac.ts
386
- function clusterRole(name) {
517
+ function clusterRole(name2) {
387
518
  return {
388
519
  apiVersion: "rbac.authorization.k8s.io/v1",
389
520
  kind: "ClusterRole",
390
- metadata: { name },
521
+ metadata: { name: name2 },
391
522
  rules: [
392
523
  {
393
524
  // @todo: make this configurable
@@ -398,35 +529,125 @@ function clusterRole(name) {
398
529
  ]
399
530
  };
400
531
  }
401
- function clusterRoleBinding(name) {
532
+ function clusterRoleBinding(name2) {
402
533
  return {
403
534
  apiVersion: "rbac.authorization.k8s.io/v1",
404
535
  kind: "ClusterRoleBinding",
405
- metadata: { name },
536
+ metadata: { name: name2 },
406
537
  roleRef: {
407
538
  apiGroup: "rbac.authorization.k8s.io",
408
539
  kind: "ClusterRole",
409
- name
540
+ name: name2
410
541
  },
411
542
  subjects: [
412
543
  {
413
544
  kind: "ServiceAccount",
414
- name,
545
+ name: name2,
415
546
  namespace: "pepr-system"
416
547
  }
417
548
  ]
418
549
  };
419
550
  }
420
- function serviceAccount(name) {
551
+ function serviceAccount(name2) {
421
552
  return {
422
553
  apiVersion: "v1",
423
554
  kind: "ServiceAccount",
424
555
  metadata: {
425
- name,
556
+ name: name2,
426
557
  namespace: "pepr-system"
427
558
  }
428
559
  };
429
560
  }
561
+ function storeRole(name2) {
562
+ name2 = `${name2}-store`;
563
+ return {
564
+ apiVersion: "rbac.authorization.k8s.io/v1",
565
+ kind: "Role",
566
+ metadata: { name: name2, namespace: "pepr-system" },
567
+ rules: [
568
+ {
569
+ apiGroups: ["pepr.dev/*"],
570
+ resources: ["peprstores"],
571
+ resourceNames: [""],
572
+ verbs: ["create", "get", "patch", "watch"]
573
+ }
574
+ ]
575
+ };
576
+ }
577
+ function storeRoleBinding(name2) {
578
+ name2 = `${name2}-store`;
579
+ return {
580
+ apiVersion: "rbac.authorization.k8s.io/v1",
581
+ kind: "RoleBinding",
582
+ metadata: { name: name2, namespace: "pepr-system" },
583
+ roleRef: {
584
+ apiGroup: "rbac.authorization.k8s.io",
585
+ kind: "Role",
586
+ name: name2
587
+ },
588
+ subjects: [
589
+ {
590
+ kind: "ServiceAccount",
591
+ name: name2,
592
+ namespace: "pepr-system"
593
+ }
594
+ ]
595
+ };
596
+ }
597
+
598
+ // src/lib/k8s.ts
599
+ var import_kubernetes_fluent_client = require("kubernetes-fluent-client");
600
+ var PeprStore = class extends import_kubernetes_fluent_client.GenericKind {
601
+ };
602
+ var peprStoreGVK = {
603
+ kind: "PeprStore",
604
+ version: "v1",
605
+ group: "pepr.dev"
606
+ };
607
+ (0, import_kubernetes_fluent_client.RegisterKind)(PeprStore, peprStoreGVK);
608
+
609
+ // src/lib/assets/store.ts
610
+ var { group, version, kind } = peprStoreGVK;
611
+ var singular = kind.toLocaleLowerCase();
612
+ var plural = `${singular}s`;
613
+ var name = `${plural}.${group}`;
614
+ var peprStoreCRD = {
615
+ apiVersion: "apiextensions.k8s.io/v1",
616
+ kind: "CustomResourceDefinition",
617
+ metadata: {
618
+ name
619
+ },
620
+ spec: {
621
+ group,
622
+ versions: [
623
+ {
624
+ // typescript doesn't know this is really already set, which is kind of annoying
625
+ name: version || "v1",
626
+ served: true,
627
+ storage: true,
628
+ schema: {
629
+ openAPIV3Schema: {
630
+ type: "object",
631
+ properties: {
632
+ data: {
633
+ type: "object",
634
+ additionalProperties: {
635
+ type: "string"
636
+ }
637
+ }
638
+ }
639
+ }
640
+ }
641
+ }
642
+ ],
643
+ scope: "Namespaced",
644
+ names: {
645
+ plural,
646
+ singular,
647
+ kind
648
+ }
649
+ }
650
+ };
430
651
 
431
652
  // src/lib/assets/webhooks.ts
432
653
  var import_ramda = require("ramda");
@@ -442,7 +663,7 @@ async function generateWebhookRules(assets, isMutateWebhook) {
442
663
  for (const capability of capabilities) {
443
664
  console.info(`Module ${config.uuid} has capability: ${capability.name}`);
444
665
  for (const binding of capability.bindings) {
445
- const { event, kind, isMutate, isValidate } = binding;
666
+ const { event, kind: kind3, isMutate, isValidate } = binding;
446
667
  if (isMutateWebhook && !isMutate) {
447
668
  continue;
448
669
  }
@@ -455,10 +676,10 @@ async function generateWebhookRules(assets, isMutateWebhook) {
455
676
  } else {
456
677
  operations.push(event);
457
678
  }
458
- const resource = kind.plural || `${kind.kind.toLowerCase()}s`;
679
+ const resource = kind3.plural || `${kind3.kind.toLowerCase()}s`;
459
680
  rules.push({
460
- apiGroups: [kind.group],
461
- apiVersions: [kind.version || "*"],
681
+ apiGroups: [kind3.group],
682
+ apiVersions: [kind3.version || "*"],
462
683
  operations,
463
684
  resources: [resource]
464
685
  });
@@ -468,7 +689,7 @@ async function generateWebhookRules(assets, isMutateWebhook) {
468
689
  }
469
690
  async function webhookConfig(assets, mutateOrValidate, timeoutSeconds = 10) {
470
691
  const ignore = [peprIgnoreLabel];
471
- const { name, tls, config, apiToken, host } = assets;
692
+ const { name: name2, tls, config, apiToken, host } = assets;
472
693
  const ignoreNS = (0, import_ramda.concat)(peprIgnoreNamespaces, config.alwaysIgnore.namespaces || []);
473
694
  if (ignoreNS) {
474
695
  ignore.push({
@@ -485,7 +706,7 @@ async function webhookConfig(assets, mutateOrValidate, timeoutSeconds = 10) {
485
706
  clientConfig.url = `https://${host}:3000${apiPath}`;
486
707
  } else {
487
708
  clientConfig.service = {
488
- name,
709
+ name: name2,
489
710
  namespace: "pepr-system",
490
711
  path: apiPath
491
712
  };
@@ -498,10 +719,10 @@ async function webhookConfig(assets, mutateOrValidate, timeoutSeconds = 10) {
498
719
  return {
499
720
  apiVersion: "admissionregistration.k8s.io/v1",
500
721
  kind: isMutate ? "MutatingWebhookConfiguration" : "ValidatingWebhookConfiguration",
501
- metadata: { name },
722
+ metadata: { name: name2 },
502
723
  webhooks: [
503
724
  {
504
- name: `${name}.pepr.dev`,
725
+ name: `${name2}.pepr.dev`,
505
726
  admissionReviewVersions: ["v1", "v1beta1"],
506
727
  clientConfig,
507
728
  failurePolicy: "Ignore",
@@ -524,137 +745,82 @@ async function webhookConfig(assets, mutateOrValidate, timeoutSeconds = 10) {
524
745
  // src/lib/assets/deploy.ts
525
746
  async function deploy(assets, webhookTimeout) {
526
747
  logger_default.info("Establishing connection to Kubernetes");
527
- const peprNS = "pepr-system";
528
- const { name, host, path } = assets;
529
- const kubeConfig = new import_client_node.KubeConfig();
530
- kubeConfig.loadFromDefault();
531
- const coreV1Api = kubeConfig.makeApiClient(import_client_node.CoreV1Api);
532
- const admissionApi = kubeConfig.makeApiClient(import_client_node.AdmissionregistrationV1Api);
533
- try {
534
- logger_default.info("Checking for namespace");
535
- await coreV1Api.readNamespace(peprNS);
536
- } catch (e) {
537
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
538
- logger_default.info("Creating namespace");
539
- await coreV1Api.createNamespace(namespace);
540
- }
748
+ const { name: name2, host, path } = assets;
749
+ logger_default.info("Applying pepr-system namespace");
750
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Namespace).Apply(namespace);
541
751
  const mutateWebhook = await webhookConfig(assets, "mutate", webhookTimeout);
542
752
  if (mutateWebhook) {
543
- try {
544
- logger_default.info("Creating mutating webhook");
545
- await admissionApi.createMutatingWebhookConfiguration(mutateWebhook);
546
- } catch (e) {
547
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
548
- logger_default.info("Removing and re-creating mutating webhook");
549
- await admissionApi.deleteMutatingWebhookConfiguration(mutateWebhook.metadata?.name ?? "");
550
- await admissionApi.createMutatingWebhookConfiguration(mutateWebhook);
551
- }
753
+ logger_default.info("Applying mutating webhook");
754
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.MutatingWebhookConfiguration).Apply(mutateWebhook);
755
+ } else {
756
+ logger_default.info("Mutating webhook not needed, removing if it exists");
757
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.MutatingWebhookConfiguration).Delete(name2);
552
758
  }
553
759
  const validateWebhook = await webhookConfig(assets, "validate", webhookTimeout);
554
760
  if (validateWebhook) {
555
- try {
556
- logger_default.info("Creating validating webhook");
557
- await admissionApi.createValidatingWebhookConfiguration(validateWebhook);
558
- } catch (e) {
559
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
560
- logger_default.info("Removing and re-creating validating webhook");
561
- await admissionApi.deleteValidatingWebhookConfiguration(validateWebhook.metadata?.name ?? "");
562
- await admissionApi.createValidatingWebhookConfiguration(validateWebhook);
563
- }
761
+ logger_default.info("Applying validating webhook");
762
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.ValidatingWebhookConfiguration).Apply(validateWebhook);
763
+ } else {
764
+ logger_default.info("Validating webhook not needed, removing if it exists");
765
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.ValidatingWebhookConfiguration).Delete(name2);
564
766
  }
767
+ logger_default.info("Applying the Pepr Store CRD if it doesn't exist");
768
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.CustomResourceDefinition).Apply(peprStoreCRD);
565
769
  if (host) {
566
770
  return;
567
771
  }
568
- if (!path) {
569
- throw new Error("No code provided");
570
- }
571
772
  const code = await import_fs.promises.readFile(path);
572
773
  const hash = import_crypto.default.createHash("sha256").update(code).digest("hex");
573
- const appsApi = kubeConfig.makeApiClient(import_client_node.AppsV1Api);
574
- const rbacApi = kubeConfig.makeApiClient(import_client_node.RbacAuthorizationV1Api);
575
- const crb = clusterRoleBinding(name);
576
- try {
577
- logger_default.info("Creating cluster role binding");
578
- await rbacApi.createClusterRoleBinding(crb);
579
- } catch (e) {
580
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
581
- logger_default.info("Removing and re-creating cluster role binding");
582
- await rbacApi.deleteClusterRoleBinding(crb.metadata?.name ?? "");
583
- await rbacApi.createClusterRoleBinding(crb);
584
- }
585
- const cr = clusterRole(name);
586
- try {
587
- logger_default.info("Creating cluster role");
588
- await rbacApi.createClusterRole(cr);
589
- } catch (e) {
590
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
591
- logger_default.info("Removing and re-creating the cluster role");
592
- try {
593
- await rbacApi.deleteClusterRole(cr.metadata?.name ?? "");
594
- await rbacApi.createClusterRole(cr);
595
- } catch (e2) {
596
- logger_default.debug(e2 instanceof import_client_node.HttpError ? e2.body : e2);
597
- }
598
- }
599
- const sa = serviceAccount(name);
600
- try {
601
- logger_default.info("Creating service account");
602
- await coreV1Api.createNamespacedServiceAccount(peprNS, sa);
603
- } catch (e) {
604
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
605
- logger_default.info("Removing and re-creating service account");
606
- await coreV1Api.deleteNamespacedServiceAccount(sa.metadata?.name ?? "", peprNS);
607
- await coreV1Api.createNamespacedServiceAccount(peprNS, sa);
608
- }
609
- const mod = moduleSecret(name, code, hash);
610
- try {
611
- logger_default.info("Creating module secret");
612
- await coreV1Api.createNamespacedSecret(peprNS, mod);
613
- } catch (e) {
614
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
615
- logger_default.info("Removing and re-creating module secret");
616
- await coreV1Api.deleteNamespacedSecret(mod.metadata?.name ?? "", peprNS);
617
- await coreV1Api.createNamespacedSecret(peprNS, mod);
618
- }
619
- const svc = service(name);
620
- try {
621
- logger_default.info("Creating service");
622
- await coreV1Api.createNamespacedService(peprNS, svc);
623
- } catch (e) {
624
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
625
- logger_default.info("Removing and re-creating service");
626
- await coreV1Api.deleteNamespacedService(svc.metadata?.name ?? "", peprNS);
627
- await coreV1Api.createNamespacedService(peprNS, svc);
628
- }
629
- const tls = tlsSecret(name, assets.tls);
630
- try {
631
- logger_default.info("Creating TLS secret");
632
- await coreV1Api.createNamespacedSecret(peprNS, tls);
633
- } catch (e) {
634
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
635
- logger_default.info("Removing and re-creating TLS secret");
636
- await coreV1Api.deleteNamespacedSecret(tls.metadata?.name ?? "", peprNS);
637
- await coreV1Api.createNamespacedSecret(peprNS, tls);
638
- }
639
- const apiToken = apiTokenSecret(name, assets.apiToken);
640
- try {
641
- logger_default.info("Creating API token secret");
642
- await coreV1Api.createNamespacedSecret(peprNS, apiToken);
643
- } catch (e) {
644
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
645
- logger_default.info("Removing and re-creating API token secret");
646
- await coreV1Api.deleteNamespacedSecret(apiToken.metadata?.name ?? "", peprNS);
647
- await coreV1Api.createNamespacedSecret(peprNS, apiToken);
774
+ if (code.length < 1) {
775
+ throw new Error("No code provided");
648
776
  }
777
+ await setupRBAC(name2);
778
+ await setupController(assets, code, hash);
779
+ await setupWatcher(assets, hash);
780
+ }
781
+ async function setupRBAC(name2) {
782
+ logger_default.info("Applying cluster role binding");
783
+ const crb = clusterRoleBinding(name2);
784
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.ClusterRoleBinding).Apply(crb);
785
+ logger_default.info("Applying cluster role");
786
+ const cr = clusterRole(name2);
787
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.ClusterRole).Apply(cr);
788
+ logger_default.info("Applying service account");
789
+ const sa = serviceAccount(name2);
790
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.ServiceAccount).Apply(sa);
791
+ logger_default.info("Applying store role");
792
+ const role = storeRole(name2);
793
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Role).Apply(role);
794
+ logger_default.info("Applying store role binding");
795
+ const roleBinding = storeRoleBinding(name2);
796
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.RoleBinding).Apply(roleBinding);
797
+ }
798
+ async function setupController(assets, code, hash) {
799
+ const { name: name2 } = assets;
800
+ logger_default.info("Applying module secret");
801
+ const mod = moduleSecret(name2, code, hash);
802
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Secret).Apply(mod);
803
+ logger_default.info("Applying controller service");
804
+ const svc = service(name2);
805
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Service).Apply(svc);
806
+ logger_default.info("Applying TLS secret");
807
+ const tls = tlsSecret(name2, assets.tls);
808
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Secret).Apply(tls);
809
+ logger_default.info("Applying API token secret");
810
+ const apiToken = apiTokenSecret(name2, assets.apiToken);
811
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Secret).Apply(apiToken);
812
+ logger_default.info("Applying deployment");
649
813
  const dep = deployment(assets, hash);
650
- try {
651
- logger_default.info("Creating deployment");
652
- await appsApi.createNamespacedDeployment(peprNS, dep);
653
- } catch (e) {
654
- logger_default.debug(e instanceof import_client_node.HttpError ? e.body : e);
655
- logger_default.info("Removing and re-creating deployment");
656
- await appsApi.deleteNamespacedDeployment(dep.metadata?.name ?? "", peprNS);
657
- await appsApi.createNamespacedDeployment(peprNS, dep);
814
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Deployment).Apply(dep);
815
+ }
816
+ async function setupWatcher(assets, hash) {
817
+ const watchDeployment = watcher(assets, hash);
818
+ if (watchDeployment) {
819
+ logger_default.info("Applying watcher deployment");
820
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Deployment).Apply(watchDeployment);
821
+ logger_default.info("Applying watcher service");
822
+ const watchSvc = watcherService(assets.name);
823
+ await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Service).Apply(watchSvc);
658
824
  }
659
825
  }
660
826
 
@@ -683,14 +849,14 @@ function loadCapabilities(path) {
683
849
  }
684
850
 
685
851
  // src/lib/assets/yaml.ts
686
- var import_client_node2 = require("@kubernetes/client-node");
852
+ var import_client_node = require("@kubernetes/client-node");
687
853
  var import_crypto2 = __toESM(require("crypto"));
688
854
  var import_fs2 = require("fs");
689
- function zarfYaml({ name, image, config }, path) {
855
+ function zarfYaml({ name: name2, image, config }, path) {
690
856
  const zarfCfg = {
691
857
  kind: "ZarfPackageConfig",
692
858
  metadata: {
693
- name,
859
+ name: name2,
694
860
  description: `Pepr Module: ${config.description}`,
695
861
  url: "https://github.com/defenseunicorns/pepr",
696
862
  version: `${config.appVersion || "0.0.1"}`
@@ -710,24 +876,29 @@ function zarfYaml({ name, image, config }, path) {
710
876
  }
711
877
  ]
712
878
  };
713
- return (0, import_client_node2.dumpYaml)(zarfCfg, { noRefs: true });
879
+ return (0, import_client_node.dumpYaml)(zarfCfg, { noRefs: true });
714
880
  }
715
881
  async function allYaml(assets) {
716
- const { name, tls, apiToken, path } = assets;
882
+ const { name: name2, tls, apiToken, path } = assets;
717
883
  const code = await import_fs2.promises.readFile(path);
718
884
  const hash = import_crypto2.default.createHash("sha256").update(code).digest("hex");
719
885
  const mutateWebhook = await webhookConfig(assets, "mutate");
720
886
  const validateWebhook = await webhookConfig(assets, "validate");
887
+ const watchDeployment = watcher(assets, hash);
721
888
  const resources = [
722
889
  namespace,
723
- clusterRole(name),
724
- clusterRoleBinding(name),
725
- serviceAccount(name),
726
- apiTokenSecret(name, apiToken),
727
- tlsSecret(name, tls),
890
+ clusterRole(name2),
891
+ clusterRoleBinding(name2),
892
+ serviceAccount(name2),
893
+ apiTokenSecret(name2, apiToken),
894
+ tlsSecret(name2, tls),
728
895
  deployment(assets, hash),
729
- service(name),
730
- moduleSecret(name, code, hash)
896
+ service(name2),
897
+ watcherService(name2),
898
+ moduleSecret(name2, code, hash),
899
+ peprStoreCRD,
900
+ storeRole(name2),
901
+ storeRoleBinding(name2)
731
902
  ];
732
903
  if (mutateWebhook) {
733
904
  resources.push(mutateWebhook);
@@ -735,7 +906,10 @@ async function allYaml(assets) {
735
906
  if (validateWebhook) {
736
907
  resources.push(validateWebhook);
737
908
  }
738
- return resources.map((r) => (0, import_client_node2.dumpYaml)(r, { noRefs: true })).join("---\n");
909
+ if (watchDeployment) {
910
+ resources.push(watchDeployment);
911
+ }
912
+ return resources.map((r) => (0, import_client_node.dumpYaml)(r, { noRefs: true })).join("---\n");
739
913
  }
740
914
 
741
915
  // src/lib/assets/index.ts
@@ -744,9 +918,6 @@ var Assets = class {
744
918
  this.config = config;
745
919
  this.path = path;
746
920
  this.host = host;
747
- this.deploy = this.deploy.bind(this);
748
- this.zarfYaml = this.zarfYaml.bind(this);
749
- this.allYaml = this.allYaml.bind(this);
750
921
  this.name = `pepr-${config.uuid}`;
751
922
  this.image = `ghcr.io/defenseunicorns/pepr/controller:v${config.peprVersion}`;
752
923
  this.tls = genTLS(this.host || `${this.name}.pepr-system.svc`);
@@ -757,21 +928,19 @@ var Assets = class {
757
928
  apiToken;
758
929
  capabilities;
759
930
  image;
760
- async deploy(webhookTimeout) {
931
+ deploy = async (webhookTimeout) => {
761
932
  this.capabilities = await loadCapabilities(this.path);
762
933
  await deploy(this, webhookTimeout);
763
- }
764
- zarfYaml(path) {
765
- return zarfYaml(this, path);
766
- }
767
- async allYaml() {
934
+ };
935
+ zarfYaml = (path) => zarfYaml(this, path);
936
+ allYaml = async () => {
768
937
  this.capabilities = await loadCapabilities(this.path);
769
938
  return allYaml(this);
770
- }
939
+ };
771
940
  };
772
941
 
773
942
  // src/cli/init/templates.ts
774
- var import_client_node3 = require("@kubernetes/client-node");
943
+ var import_client_node2 = require("@kubernetes/client-node");
775
944
  var import_util = require("util");
776
945
  var import_uuid = require("uuid");
777
946
 
@@ -976,8 +1145,8 @@ var hello_pepr_samples_default = [
976
1145
  var gitIgnore = "# Ignore node_modules and Pepr build artifacts\nnode_modules\ndist\ninsecure*\n";
977
1146
  var readmeMd = '# Pepr Module\n\nThis is a Pepr Module. [Pepr](https://github.com/defenseunicorns/pepr) is a type-safe Kubernetes middleware system.\n\nThe `capabilities` directory contains all the capabilities for this module. By default,\na capability is a single typescript file in the format of `capability-name.ts` that is\nimported in the root `pepr.ts` file as `import { HelloPepr } from "./capabilities/hello-pepr";`.\nBecause this is typescript, you can organize this however you choose, e.g. creating a sub-folder\nper-capability or common logic in shared files or folders.\n\nExample Structure:\n\n```\nModule Root\n\u251C\u2500\u2500 package.json\n\u251C\u2500\u2500 pepr.ts\n\u2514\u2500\u2500 capabilities\n \u251C\u2500\u2500 example-one.ts\n \u251C\u2500\u2500 example-three.ts\n \u2514\u2500\u2500 example-two.ts\n```\n';
978
1147
  var peprTS = 'import { PeprModule } from "pepr";\n// cfg loads your pepr configuration from package.json\nimport cfg from "./package.json";\n\n// HelloPepr is a demo capability that is included with Pepr. Comment or delete the line below to remove it.\nimport { HelloPepr } from "./capabilities/hello-pepr";\n\n/**\n * This is the main entrypoint for this Pepr module. It is run when the module is started.\n * This is where you register your Pepr configurations and capabilities.\n */\nnew PeprModule(cfg, [\n // "HelloPepr" is a demo capability that is included with Pepr. Comment or delete the line below to remove it.\n HelloPepr,\n\n // Your additional capabilities go here\n]);\n';
979
- var helloPeprTS = 'import {\n Capability,\n Log,\n PeprMutateRequest,\n RegisterKind,\n a,\n fetch,\n fetchStatus,\n} from "pepr";\n\n/**\n * The HelloPepr Capability is an example capability to demonstrate some general concepts of Pepr.\n * To test this capability you run `pepr dev`and then run the following command:\n * `kubectl apply -f capabilities/hello-pepr.samples.yaml`\n */\nexport const HelloPepr = new Capability({\n name: "hello-pepr",\n description: "A simple example capability to show how things work.",\n namespaces: ["pepr-demo", "pepr-demo-2"],\n});\n\n// Use the \'When\' function to create a new Action\nconst { When } = HelloPepr;\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action removes the label `remove-me` when a Namespace is created.\n * Note we don\'t need to specify the namespace here, because we\'ve already specified\n * it in the Capability definition above.\n */\nWhen(a.Namespace)\n .IsCreated()\n .Mutate(ns => ns.RemoveLabel("remove-me"));\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 1) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is a single action. They can be in the same file or put imported from other files.\n * In this example, when a ConfigMap is created with the name `example-1`, then add a label and annotation.\n *\n * Equivalent to manually running:\n * `kubectl label configmap example-1 pepr=was-here`\n * `kubectl annotate configmap example-1 pepr.dev=annotations-work-too`\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request\n .SetLabel("pepr", "was-here")\n .SetAnnotation("pepr.dev", "annotations-work-too");\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate & Validate Actions (CM Example 2) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This combines 2 different types of actions: \'Mutate\', and \'Validate\'. The order\n * of the actions is required, but each action is optional. In this example, when a ConfigMap is created\n * with the name `example-2`, then add a label and annotation and finally validate that the ConfigMap has the label\n * `pepr`.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n // This Mutate Action will mutate the request before it is persisted to the cluster\n\n // Use `request.Merge()` to merge the new data with the existing data\n request.Merge({\n metadata: {\n labels: {\n pepr: "was-here",\n },\n annotations: {\n "pepr.dev": "annotations-work-too",\n },\n },\n });\n })\n .Validate(request => {\n // This Validate Action will validate the request before it is persisted to the cluster\n\n // Approve the request if the ConfigMap has the label \'pepr\'\n if (request.HasLabel("pepr")) {\n return request.Approve();\n }\n\n // Otherwise, deny the request with an error message (optional)\n return request.Deny("ConfigMap must have label \'pepr\'");\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 2a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action shows a simple validation that will deny any ConfigMap that has the\n * annotation `evil`. Note that the `Deny()` function takes an optional second parameter that is a\n * user-defined status code to return.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .Validate(request => {\n if (request.HasAnnotation("evil")) {\n return request.Deny("No evil CM annotations allowed.", 400);\n }\n\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 3) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action combines different styles. Unlike the previous actions, this one will look\n * for any ConfigMap in the `pepr-demo` namespace that has the label `change=by-label` during either\n * CREATE or UPDATE. Note that all conditions added such as `WithName()`, `WithLabel()`, `InNamespace()`,\n * are ANDs so all conditions must be true for the request to be processed.\n */\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("change", "by-label")\n .Mutate(request => {\n // The K8s object e are going to mutate\n const cm = request.Raw;\n\n // Get the username and uid of the K8s request\n const { username, uid } = request.Request.userInfo;\n\n // Store some data about the request in the configmap\n cm.data["username"] = username;\n cm.data["uid"] = uid;\n\n // You can still mix other ways of making changes too\n request.SetAnnotation("pepr.dev", "making-waves");\n });\n\n// This action validates the label `change=by-label` is deleted\nWhen(a.ConfigMap)\n .IsDeleted()\n .WithLabel("change", "by-label")\n .Validate(request => {\n // Log and then always approve the request\n Log.info("CM with label \'change=by-label\' was deleted.");\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action show how you can use the `Mutate()` function without an inline function.\n * This is useful if you want to keep your actions small and focused on a single task,\n * or if you want to reuse the same function in multiple actions.\n */\nWhen(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);\n\n// This function uses the complete type definition, but is not required.\nfunction example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {\n cm.SetLabel("pepr.dev/first", "true");\n cm.SetLabel("pepr.dev/second", "true");\n cm.SetLabel("pepr.dev/third", "true");\n}\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is the same as Example 4, except this only operates on a CM in the `pepr-demo-2` namespace.\n * Note because the Capability defines namespaces, the namespace specified here must be one of those.\n * Alternatively, you can remove the namespace from the Capability definition and specify it here.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .InNamespace("pepr-demo-2")\n .WithName("example-4a")\n .Mutate(example4Cb);\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 5) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action is a bit more complex. It will look for any ConfigMap in the `pepr-demo`\n * namespace that has the label `chuck-norris` during CREATE. When it finds one, it will fetch a\n * random Chuck Norris joke from the API and add it to the ConfigMap. This is a great example of how\n * you can use Pepr to make changes to your K8s objects based on external data.\n *\n * Note the use of the `async` keyword. This is required for any action that uses `await` or `fetch()`.\n *\n * Also note we are passing a type to the `fetch()` function. This is optional, but it will help you\n * avoid mistakes when working with the data returned from the API. You can also use the `as` keyword to\n * cast the data returned from the API.\n *\n * These are equivalent:\n * ```ts\n * const joke = await fetch<TheChuckNorrisJoke>("https://api.chucknorris.io/jokes/random?category=dev");\n * const joke = await fetch("https://api.chucknorris.io/jokes/random?category=dev") as TheChuckNorrisJoke;\n * ```\n *\n * Alternatively, you can drop the type completely:\n *\n * ```ts\n * fetch("https://api.chucknorris.io/jokes/random?category=dev")\n * ```\n */\ninterface TheChuckNorrisJoke {\n icon_url: string;\n id: string;\n url: string;\n value: string;\n}\n\nWhen(a.ConfigMap)\n .IsCreated()\n .WithLabel("chuck-norris")\n .Mutate(async change => {\n // Try/catch is not needed as a response object will always be returned\n const response = await fetch<TheChuckNorrisJoke>(\n "https://api.chucknorris.io/jokes/random?category=dev",\n );\n\n // Instead, check the `response.ok` field\n if (response.ok) {\n // Add the Chuck Norris joke to the configmap\n change.Raw.data["chuck-says"] = response.data.value;\n return;\n }\n\n // You can also assert on different HTTP response codes\n if (response.status === fetchStatus.NOT_FOUND) {\n // Do something else\n return;\n }\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Secret Base64 Handling) *\n * ---------------------------------------------------------------------------------------------------\n *\n * The K8s JS client provides incomplete support for base64 encoding/decoding handling for secrets,\n * unlike the GO client. To make this less painful, Pepr automatically handles base64 encoding/decoding\n * secret data before and after the action is executed.\n */\nWhen(a.Secret)\n .IsCreated()\n .WithName("secret-1")\n .Mutate(request => {\n const secret = request.Raw;\n\n // This will be encoded at the end of all processing back to base64: "Y2hhbmdlLXdpdGhvdXQtZW5jb2Rpbmc="\n secret.data.magic = "change-without-encoding";\n\n // You can modify the data directly, and it will be encoded at the end of all processing\n secret.data.example += " - modified by Pepr";\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Untyped Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * Out of the box, Pepr supports all the standard Kubernetes objects. However, you can also create\n * your own types. This is useful if you are working with an Operator that creates custom resources.\n * There are two ways to do this, the first is to use the `When()` function with a `GenericKind`,\n * the second is to create a new class that extends `GenericKind` and use the `RegisterKind()` function.\n *\n * This example shows how to use the `When()` function with a `GenericKind`. Note that you\n * must specify the `group`, `version`, and `kind` of the object (if applicable). This is how Pepr knows\n * if the action should be triggered or not. Since we are using a `GenericKind`,\n * Pepr will not be able to provide any intellisense for the object, so you will need to refer to the\n * Kubernetes API documentation for the object you are working with.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-1\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```\n */\nWhen(a.GenericKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n})\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr without type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Typed Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This example shows how to use the `RegisterKind()` function to create a new type. This is useful\n * if you are working with an Operator that creates custom resources and you want to have intellisense\n * for the object. Note that you must specify the `group`, `version`, and `kind` of the object (if applicable)\n * as this is how Pepr knows if the action should be triggered or not.\n *\n * Once you register a new Kind with Pepr, you can use the `When()` function with the new Kind. Ideally,\n * you should register custom Kinds at the top of your Capability file or Pepr Module so they are available\n * to all actions, but we are putting it here for demonstration purposes.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-2\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```*\n */\nclass UnicornKind extends a.GenericKind {\n spec: {\n /**\n * JSDoc comments can be added to explain more details about the field.\n *\n * @example\n * ```ts\n * request.Raw.spec.message = "Hello Pepr!";\n * ```\n * */\n message: string;\n counter: number;\n };\n}\n\nRegisterKind(UnicornKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n});\n\nWhen(UnicornKind)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr with type data!",\n counter: Math.random(),\n },\n });\n });\n';
980
- var packageJSON = { name: "pepr", description: "Kubernetes application engine", author: "Defense Unicorns", homepage: "https://github.com/defenseunicorns/pepr", license: "Apache-2.0", bin: "dist/cli.js", repository: "defenseunicorns/pepr", engines: { node: ">=18.0.0" }, version: "0.13.4", main: "dist/lib.js", types: "dist/lib.d.ts", scripts: { "gen-data-json": "node hack/build-template-data.js", prebuild: "rm -fr dist/* && npm run gen-data-json", build: "tsc && node build.mjs", test: "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage", "test:journey": "npm run test:journey:k3d && npm run test:journey:build && npm run test:journey:image && npm run test:journey:run", "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0'", "test:journey:build": "npm run build && npm pack", "test:journey:image": "docker buildx build --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev", "test:journey:run": "jest journey/entrypoint.test.ts", "format:check": "eslint src && prettier src --check", "format:fix": "eslint src --fix && prettier src --write" }, dependencies: { "@kubernetes/client-node": "0.19.0", express: "4.18.2", "fast-json-patch": "3.1.1", "http-status-codes": "2.2.0", "node-fetch": "2.7.0", pino: "8.15.1", "pino-pretty": "10.2.0", "prom-client": "14.2.0", ramda: "0.29.0" }, devDependencies: { "@jest/globals": "29.7.0", "@types/eslint": "8.44.2", "@types/express": "4.17.17", "@types/node": "18.x.x", "@types/node-fetch": "2.6.4", "@types/node-forge": "1.3.5", "@types/prettier": "3.0.0", "@types/prompts": "2.4.4", "@types/ramda": "0.29.4", "@types/uuid": "9.0.4", jest: "29.7.0", nock: "13.3.3", "ts-jest": "29.1.1" }, peerDependencies: { "@typescript-eslint/eslint-plugin": "6.5.0", "@typescript-eslint/parser": "6.5.0", commander: "11.0.0", esbuild: "0.19.2", eslint: "8.48.0", "node-forge": "1.3.1", prettier: "3.0.3", prompts: "2.4.2", typescript: "5.2.2", uuid: "9.0.0" } };
1148
+ var helloPeprTS = 'import {\n Capability,\n K8s,\n Log,\n PeprMutateRequest,\n RegisterKind,\n a,\n fetch,\n fetchStatus,\n kind,\n} from "pepr";\n\n/**\n * The HelloPepr Capability is an example capability to demonstrate some general concepts of Pepr.\n * To test this capability you run `pepr dev`and then run the following command:\n * `kubectl apply -f capabilities/hello-pepr.samples.yaml`\n */\nexport const HelloPepr = new Capability({\n name: "hello-pepr",\n description: "A simple example capability to show how things work.",\n namespaces: ["pepr-demo", "pepr-demo-2"],\n});\n\n// Use the \'When\' function to create a new action, use \'Store\' to persist data\nconst { When, Store } = HelloPepr;\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action removes the label `remove-me` when a Namespace is created.\n * Note we don\'t need to specify the namespace here, because we\'ve already specified\n * it in the Capability definition above.\n */\nWhen(a.Namespace)\n .IsCreated()\n .Mutate(ns => ns.RemoveLabel("remove-me"));\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Watch Action with K8s SSA (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action watches for the `pepr-demo-2` namespace to be created, then creates a ConfigMap with\n * the name `pepr-ssa-demo` and adds the namespace UID to the ConfigMap data. Because Pepr uses\n * server-side apply for this operation, the ConfigMap will be created or updated if it already exists.\n */\nWhen(a.Namespace)\n .IsCreated()\n .WithName("pepr-demo-2")\n .Watch(async ns => {\n Log.info("Namespace pepr-demo-2 was created.");\n\n // You can share data between actions using the Store, including between different types of actions\n Store.setItem("watch-data", "This data was stored by a Watch Action.");\n\n // Apply the ConfigMap using K8s server-side apply\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: "pepr-ssa-demo",\n namespace: "pepr-demo-2",\n },\n data: {\n "ns-uid": ns.metadata.uid,\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 1) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is a single action. They can be in the same file or put imported from other files.\n * In this example, when a ConfigMap is created with the name `example-1`, then add a label and annotation.\n *\n * Equivalent to manually running:\n * `kubectl label configmap example-1 pepr=was-here`\n * `kubectl annotate configmap example-1 pepr.dev=annotations-work-too`\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request\n .SetLabel("pepr", "was-here")\n .SetAnnotation("pepr.dev", "annotations-work-too");\n\n // Use the Store to persist data between requests and Pepr controller pods\n Store.setItem("example-1", "was-here");\n\n // This data is written asynchronously and can be read back via `Store.getItem()` or `Store.subscribe()`\n Store.setItem("example-1-data", JSON.stringify(request.Raw.data));\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate & Validate Actions (CM Example 2) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This combines 3 different types of actions: \'Mutate\', \'Validate\', and \'Watch\'. The order\n * of the actions is required, but each action is optional. In this example, when a ConfigMap is created\n * with the name `example-2`, then add a label and annotation, validate that the ConfigMap has the label\n * `pepr`, and log the request.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n // This Mutate Action will mutate the request before it is persisted to the cluster\n\n // Use `request.Merge()` to merge the new data with the existing data\n request.Merge({\n metadata: {\n labels: {\n pepr: "was-here",\n },\n annotations: {\n "pepr.dev": "annotations-work-too",\n },\n },\n });\n })\n .Validate(request => {\n // This Validate Action will validate the request before it is persisted to the cluster\n\n // Approve the request if the ConfigMap has the label \'pepr\'\n if (request.HasLabel("pepr")) {\n return request.Approve();\n }\n\n // Otherwise, deny the request with an error message (optional)\n return request.Deny("ConfigMap must have label \'pepr\'");\n })\n .Watch((cm, phase) => {\n // This Watch Action will watch the ConfigMap after it has been persisted to the cluster\n Log.info(cm, `ConfigMap was ${phase} with the name example-2`);\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 2a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action shows a simple validation that will deny any ConfigMap that has the\n * annotation `evil`. Note that the `Deny()` function takes an optional second parameter that is a\n * user-defined status code to return.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .Validate(request => {\n if (request.HasAnnotation("evil")) {\n return request.Deny("No evil CM annotations allowed.", 400);\n }\n\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 3) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action combines different styles. Unlike the previous actions, this one will look\n * for any ConfigMap in the `pepr-demo` namespace that has the label `change=by-label` during either\n * CREATE or UPDATE. Note that all conditions added such as `WithName()`, `WithLabel()`, `InNamespace()`,\n * are ANDs so all conditions must be true for the request to be processed.\n */\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("change", "by-label")\n .Mutate(request => {\n // The K8s object e are going to mutate\n const cm = request.Raw;\n\n // Get the username and uid of the K8s request\n const { username, uid } = request.Request.userInfo;\n\n // Store some data about the request in the configmap\n cm.data["username"] = username;\n cm.data["uid"] = uid;\n\n // You can still mix other ways of making changes too\n request.SetAnnotation("pepr.dev", "making-waves");\n });\n\n// This action validates the label `change=by-label` is deleted\nWhen(a.ConfigMap)\n .IsDeleted()\n .WithLabel("change", "by-label")\n .Validate(request => {\n // Log and then always approve the request\n Log.info("CM with label \'change=by-label\' was deleted.");\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action show how you can use the `Mutate()` function without an inline function.\n * This is useful if you want to keep your actions small and focused on a single task,\n * or if you want to reuse the same function in multiple actions.\n */\nWhen(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);\n\n// This function uses the complete type definition, but is not required.\nfunction example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {\n cm.SetLabel("pepr.dev/first", "true");\n cm.SetLabel("pepr.dev/second", "true");\n cm.SetLabel("pepr.dev/third", "true");\n}\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is the same as Example 4, except this only operates on a CM in the `pepr-demo-2` namespace.\n * Note because the Capability defines namespaces, the namespace specified here must be one of those.\n * Alternatively, you can remove the namespace from the Capability definition and specify it here.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .InNamespace("pepr-demo-2")\n .WithName("example-4a")\n .Mutate(example4Cb);\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 5) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action is a bit more complex. It will look for any ConfigMap in the `pepr-demo`\n * namespace that has the label `chuck-norris` during CREATE. When it finds one, it will fetch a\n * random Chuck Norris joke from the API and add it to the ConfigMap. This is a great example of how\n * you can use Pepr to make changes to your K8s objects based on external data.\n *\n * Note the use of the `async` keyword. This is required for any action that uses `await` or `fetch()`.\n *\n * Also note we are passing a type to the `fetch()` function. This is optional, but it will help you\n * avoid mistakes when working with the data returned from the API. You can also use the `as` keyword to\n * cast the data returned from the API.\n *\n * These are equivalent:\n * ```ts\n * const joke = await fetch<TheChuckNorrisJoke>("https://api.chucknorris.io/jokes/random?category=dev");\n * const joke = await fetch("https://api.chucknorris.io/jokes/random?category=dev") as TheChuckNorrisJoke;\n * ```\n *\n * Alternatively, you can drop the type completely:\n *\n * ```ts\n * fetch("https://api.chucknorris.io/jokes/random?category=dev")\n * ```\n */\ninterface TheChuckNorrisJoke {\n icon_url: string;\n id: string;\n url: string;\n value: string;\n}\n\nWhen(a.ConfigMap)\n .IsCreated()\n .WithLabel("chuck-norris")\n .Mutate(async change => {\n // Try/catch is not needed as a response object will always be returned\n const response = await fetch<TheChuckNorrisJoke>(\n "https://api.chucknorris.io/jokes/random?category=dev",\n );\n\n // Instead, check the `response.ok` field\n if (response.ok) {\n // Add the Chuck Norris joke to the configmap\n change.Raw.data["chuck-says"] = response.data.value;\n return;\n }\n\n // You can also assert on different HTTP response codes\n if (response.status === fetchStatus.NOT_FOUND) {\n // Do something else\n return;\n }\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Secret Base64 Handling) *\n * ---------------------------------------------------------------------------------------------------\n *\n * The K8s JS client provides incomplete support for base64 encoding/decoding handling for secrets,\n * unlike the GO client. To make this less painful, Pepr automatically handles base64 encoding/decoding\n * secret data before and after the action is executed.\n */\nWhen(a.Secret)\n .IsCreated()\n .WithName("secret-1")\n .Mutate(request => {\n const secret = request.Raw;\n\n // This will be encoded at the end of all processing back to base64: "Y2hhbmdlLXdpdGhvdXQtZW5jb2Rpbmc="\n secret.data.magic = "change-without-encoding";\n\n // You can modify the data directly, and it will be encoded at the end of all processing\n secret.data.example += " - modified by Pepr";\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Untyped Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * Out of the box, Pepr supports all the standard Kubernetes objects. However, you can also create\n * your own types. This is useful if you are working with an Operator that creates custom resources.\n * There are two ways to do this, the first is to use the `When()` function with a `GenericKind`,\n * the second is to create a new class that extends `GenericKind` and use the `RegisterKind()` function.\n *\n * This example shows how to use the `When()` function with a `GenericKind`. Note that you\n * must specify the `group`, `version`, and `kind` of the object (if applicable). This is how Pepr knows\n * if the action should be triggered or not. Since we are using a `GenericKind`,\n * Pepr will not be able to provide any intellisense for the object, so you will need to refer to the\n * Kubernetes API documentation for the object you are working with.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-1\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```\n */\nWhen(a.GenericKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n})\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr without type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Typed Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This example shows how to use the `RegisterKind()` function to create a new type. This is useful\n * if you are working with an Operator that creates custom resources and you want to have intellisense\n * for the object. Note that you must specify the `group`, `version`, and `kind` of the object (if applicable)\n * as this is how Pepr knows if the action should be triggered or not.\n *\n * Once you register a new Kind with Pepr, you can use the `When()` function with the new Kind. Ideally,\n * you should register custom Kinds at the top of your Capability file or Pepr Module so they are available\n * to all actions, but we are putting it here for demonstration purposes.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-2\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```*\n */\nclass UnicornKind extends a.GenericKind {\n spec: {\n /**\n * JSDoc comments can be added to explain more details about the field.\n *\n * @example\n * ```ts\n * request.Raw.spec.message = "Hello Pepr!";\n * ```\n * */\n message: string;\n counter: number;\n };\n}\n\nRegisterKind(UnicornKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n});\n\nWhen(UnicornKind)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr with type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * A callback function that is called once the Pepr Store is fully loaded.\n */\nStore.onReady(data => {\n Log.info(data, "Pepr Store Ready");\n});\n';
1149
+ var packageJSON = { name: "pepr", description: "Kubernetes application engine", author: "Defense Unicorns", homepage: "https://github.com/defenseunicorns/pepr", license: "Apache-2.0", bin: "dist/cli.js", repository: "defenseunicorns/pepr", engines: { node: ">=18.0.0" }, version: "0.14.1", main: "dist/lib.js", types: "dist/lib.d.ts", scripts: { "gen-data-json": "node hack/build-template-data.js", prebuild: "rm -fr dist/* && npm run gen-data-json", build: "tsc && node build.mjs", test: "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage", "test:journey": "npm run test:journey:k3d && npm run test:journey:build && npm run test:journey:image && npm run test:journey:run", "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0'", "test:journey:build": "npm run build && npm pack", "test:journey:image": "docker buildx build --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev", "test:journey:run": "jest journey/entrypoint.test.ts", "format:check": "eslint src && prettier src --check", "format:fix": "eslint src --fix && prettier src --write" }, dependencies: { express: "4.18.2", "fast-json-patch": "3.1.1", "kubernetes-fluent-client": "1.6.0", pino: "8.16.0", "pino-pretty": "10.2.3", "prom-client": "15.0.0", ramda: "0.29.1" }, devDependencies: { "@commitlint/cli": "17.7.2", "@commitlint/config-conventional": "17.7.0", "@jest/globals": "29.7.0", "@types/eslint": "8.44.4", "@types/express": "4.17.19", "@types/node": "18.x.x", "@types/node-forge": "1.3.7", "@types/prompts": "2.4.6", "@types/ramda": "0.29.6", "@types/uuid": "9.0.5", jest: "29.7.0", nock: "13.3.4", "ts-jest": "29.1.1" }, peerDependencies: { "@typescript-eslint/eslint-plugin": "6.7.3", "@typescript-eslint/parser": "6.7.3", commander: "11.0.0", esbuild: "0.19.4", eslint: "8.50.0", "node-forge": "1.3.1", prettier: "3.0.3", prompts: "2.4.2", typescript: "5.2.2", uuid: "9.0.1" } };
981
1150
 
982
1151
  // src/templates/pepr.code-snippets.json
983
1152
  var pepr_code_snippets_default = {
@@ -1036,8 +1205,8 @@ var tsconfig_module_default = {
1036
1205
 
1037
1206
  // src/cli/init/utils.ts
1038
1207
  var import_fs3 = require("fs");
1039
- function sanitizeName(name) {
1040
- let sanitized = name.toLowerCase().replace(/[^a-z0-9-]+/gi, "-");
1208
+ function sanitizeName(name2) {
1209
+ let sanitized = name2.toLowerCase().replace(/[^a-z0-9-]+/gi, "-");
1041
1210
  sanitized = sanitized.replace(/^-+|-+$/g, "");
1042
1211
  sanitized = sanitized.replace(/--+/g, "-");
1043
1212
  return sanitized;
@@ -1061,13 +1230,13 @@ function write(path, data) {
1061
1230
  }
1062
1231
 
1063
1232
  // src/cli/init/templates.ts
1064
- var { dependencies, devDependencies, peerDependencies, scripts, version } = packageJSON;
1233
+ var { dependencies, devDependencies, peerDependencies, scripts, version: version2 } = packageJSON;
1065
1234
  function genPkgJSON(opts, pgkVerOverride) {
1066
1235
  const uuid = (0, import_uuid.v5)(opts.name, (0, import_uuid.v4)());
1067
- const name = sanitizeName(opts.name);
1236
+ const name2 = sanitizeName(opts.name);
1068
1237
  const { typescript } = peerDependencies;
1069
1238
  const data = {
1070
- name,
1239
+ name: name2,
1071
1240
  version: "0.0.1",
1072
1241
  description: opts.description,
1073
1242
  keywords: ["pepr", "k8s", "policy-engine", "pepr-module", "security"],
@@ -1087,7 +1256,7 @@ function genPkgJSON(opts, pgkVerOverride) {
1087
1256
  "k3d-setup": scripts["test:journey:k3d"]
1088
1257
  },
1089
1258
  dependencies: {
1090
- pepr: pgkVerOverride || version
1259
+ pepr: pgkVerOverride || version2
1091
1260
  },
1092
1261
  devDependencies: {
1093
1262
  typescript
@@ -1119,7 +1288,7 @@ var gitignore = {
1119
1288
  };
1120
1289
  var samplesYaml = {
1121
1290
  path: "hello-pepr.samples.yaml",
1122
- data: hello_pepr_samples_default.map((r) => (0, import_client_node3.dumpYaml)(r, { noRefs: true })).join("---\n")
1291
+ data: hello_pepr_samples_default.map((r) => (0, import_client_node2.dumpYaml)(r, { noRefs: true })).join("---\n")
1123
1292
  };
1124
1293
  var snippet = {
1125
1294
  path: "pepr.code-snippets",
@@ -1230,6 +1399,7 @@ function build_default(program2) {
1230
1399
  }
1231
1400
  var externalLibs = Object.keys(dependencies);
1232
1401
  externalLibs.push("pepr");
1402
+ externalLibs.push("@kubernetes/client-node");
1233
1403
  async function loadModule(entryPoint = peprTS2) {
1234
1404
  const cfgPath = (0, import_path.resolve)(".", "package.json");
1235
1405
  const input = (0, import_path.resolve)(".", entryPoint);
@@ -1245,16 +1415,16 @@ async function loadModule(entryPoint = peprTS2) {
1245
1415
  const moduleText = await import_fs5.promises.readFile(cfgPath, { encoding: "utf-8" });
1246
1416
  const cfg = JSON.parse(moduleText);
1247
1417
  const { uuid } = cfg.pepr;
1248
- const name = `pepr-${uuid}.js`;
1249
- cfg.pepr.peprVersion = version;
1418
+ const name2 = `pepr-${uuid}.js`;
1419
+ cfg.pepr.peprVersion = version2;
1250
1420
  if (!uuid) {
1251
1421
  throw new Error("Could not load the uuid in package.json");
1252
1422
  }
1253
1423
  return {
1254
1424
  cfg,
1255
1425
  input,
1256
- name,
1257
- path: (0, import_path.resolve)("dist", name),
1426
+ name: name2,
1427
+ path: (0, import_path.resolve)("dist", name2),
1258
1428
  uuid
1259
1429
  };
1260
1430
  }
@@ -1419,6 +1589,7 @@ function dev_default(program2) {
1419
1589
  env: {
1420
1590
  ...process.env,
1421
1591
  LOG_LEVEL: "debug",
1592
+ PEPR_MODE: "dev",
1422
1593
  PEPR_API_TOKEN: webhook.apiToken,
1423
1594
  PEPR_PRETTY_LOGS: "true",
1424
1595
  SSL_KEY_PATH: "insecure-tls.key",
@@ -1471,8 +1642,8 @@ function walkthrough() {
1471
1642
  message: "Enter a name for the new Pepr module. This will create a new directory based on the name.\n",
1472
1643
  validate: async (val) => {
1473
1644
  try {
1474
- const name = sanitizeName(val);
1475
- await import_fs7.promises.access(name, import_fs7.promises.constants.F_OK);
1645
+ const name2 = sanitizeName(val);
1646
+ await import_fs7.promises.access(name2, import_fs7.promises.constants.F_OK);
1476
1647
  return "A directory with this name already exists";
1477
1648
  } catch (e) {
1478
1649
  return val.length > 2 || "The name must be at least 3 characters long";
@@ -1595,8 +1766,8 @@ function init_default(program2) {
1595
1766
  var import_commander = require("commander");
1596
1767
  var RootCmd = class extends import_commander.Command {
1597
1768
  // eslint-disable-next-line class-methods-use-this
1598
- createCommand(name) {
1599
- const cmd = new import_commander.Command(name);
1769
+ createCommand(name2) {
1770
+ const cmd = new import_commander.Command(name2);
1600
1771
  cmd.option("-l, --log-level [level]", "Log level: debug, info, warn, error", "info");
1601
1772
  cmd.hook("preAction", (run) => {
1602
1773
  logger_default.level = run.opts().logLevel;
@@ -1668,7 +1839,7 @@ if (process.env.npm_lifecycle_event !== "npx") {
1668
1839
  console.warn("Pepr should be run via `npx pepr <command>` instead of `pepr <command>`.");
1669
1840
  }
1670
1841
  var program = new RootCmd();
1671
- program.version(version).description(`Pepr (v${version}) - Type safe K8s middleware for humans`).action(() => {
1842
+ program.version(version2).description(`Pepr (v${version2}) - Type safe K8s middleware for humans`).action(() => {
1672
1843
  if (program.args.length < 1) {
1673
1844
  console.log(banner);
1674
1845
  program.help();